Odpowiedzi:
W GNU find
możesz do tego użyć -printf
parametru, np .:
find /dir1 -type f -printf "%f\n"
-o
Ma niższy priorytet niż sugerowany -a
, więc często będziesz chciał pogrupować swoje -o
argumenty)
Jeśli twoje wyszukiwanie nie ma opcji -printf, możesz także użyć basename:
find ./dir1 -type f -exec basename {} \;
... {} ';'
Użyj, -execdir
która automatycznie przechowuje bieżący plik {}
, na przykład:
find . -type f -execdir echo '{}' ';'
Możesz także użyć $PWD
zamiast .
(w niektórych systemach nie będzie generować dodatkowej kropki z przodu).
Jeśli nadal masz dodatkową kropkę, możesz uruchomić:
find . -type f -execdir basename '{}' ';'
-execdir utility [argument ...] ;
-execdir
Podstawowy jest identyczny z-exec
pierwotnym z wyjątkiem tego, że narzędzie będzie wykonywany z katalogu, który posiada aktualny plik .
Jeśli zostanie użyty +
zamiast ;
, to {}
zostanie zastąpiony jak największą liczbą ścieżek dla każdego wywołania narzędzia. Innymi słowy, wypisze wszystkie nazwy plików w jednym wierszu.
./filename
zamiast filename
. W zależności od potrzeb może być lub nie być w porządku.
$PWD
zamiast .
.
Jeśli używasz GNU find
find . -type f -printf "%f\n"
Lub możesz użyć języka programowania, takiego jak Ruby (1.9+)
$ ruby -e 'Dir["**/*"].each{|x| puts File.basename(x)}'
Jeśli masz ochotę na bash (co najmniej 4) rozwiązanie
shopt -s globstar
for file in **; do echo ${file##*/}; done
Jeśli chcesz uruchomić jakieś działanie tylko przeciwko nazwie pliku, użycie basename
może być trudne.
Na przykład to:
find ~/clang+llvm-3.3/bin/ -type f -exec echo basename {} \;
po prostu wyśle echo basename /my/found/path
. Nie to, co chcemy, jeśli chcemy wykonać na nazwie pliku.
Ale możesz wtedy uzyskać xargs
wynik. na przykład, aby zabić pliki w katalogu na podstawie nazw w innym katalogu:
cd dirIwantToRMin;
find ~/clang+llvm-3.3/bin/ -type f -exec basename {} \; | xargs rm
find ~/clang+llvm-3.3/bin/ -type f -exec basename {} \;
-exec
i -execdir
są powolne, xargs
jest królem.
$ alias f='time find /Applications -name "*.app" -type d -maxdepth 5'; \
f -exec basename {} \; | wc -l; \
f -execdir echo {} \; | wc -l; \
f -print0 | xargs -0 -n1 basename | wc -l; \
f -print0 | xargs -0 -n1 -P 8 basename | wc -l; \
f -print0 | xargs -0 basename | wc -l
139
0m01.17s real 0m00.20s user 0m00.93s system
139
0m01.16s real 0m00.20s user 0m00.92s system
139
0m01.05s real 0m00.17s user 0m00.85s system
139
0m00.93s real 0m00.17s user 0m00.85s system
139
0m00.88s real 0m00.12s user 0m00.75s system
xargs
Równoległość pomaga również.
Co zabawne, nie potrafię wyjaśnić ostatniego przypadku xargs
bez -n1
. Daje poprawny wynik i jest najszybszy¯\_(ツ)_/¯
( basename
pobiera tylko 1 argument ścieżki, ale xargs
wyśle je wszystkie (właściwie 5000) bez -n1
. nie działa na systemie Linux i openbsd, tylko macOS ...)
Niektóre większe liczby z systemu Linux, aby zobaczyć, jak -execdir
pomaga, ale wciąż znacznie wolniej niż równolegle xargs
:
$ alias f='time find /usr/ -maxdepth 5 -type d'
$ f -exec basename {} \; | wc -l; \
f -execdir echo {} \; | wc -l; \
f -print0 | xargs -0 -n1 basename | wc -l; \
f -print0 | xargs -0 -n1 -P 8 basename | wc -l
2358
3.63s real 0.10s user 0.41s system
2358
1.53s real 0.05s user 0.31s system
2358
1.30s real 0.03s user 0.21s system
2358
0.41s real 0.03s user 0.25s system
find
jest to -execdir
, że staje się najszybciej jak tworzenie nowych procesów jest stosunkowo kosztowna operacja.
Jak zauważyli inni, możesz łączyć find
i basename
, ale domyślnie basename
program będzie działał tylko na jednej ścieżce na raz, więc plik wykonywalny będzie musiał zostać uruchomiony raz dla każdej ścieżki (przy użyciu jednego find ... -exec
lub dwóch find ... | xargs -n 1
), co może być potencjalnie wolne.
Jeśli użyjesz tej -a
opcji basename
, może zaakceptować wiele nazw plików w jednym wywołaniu, co oznacza, że możesz użyć xargs
bez -n 1
, aby pogrupować ścieżki w znacznie mniejszą liczbę wywołań basename
, co powinno być bardziej wydajne.
Przykład:
find /dir1 -type f -print0 | xargs -0 basename -a
Tutaj umieściłem -print0
i -0
(które powinny być używane razem), aby poradzić sobie z dowolnymi spacjami w nazwach plików i katalogów.
Oto porównanie czasowe między wersjami xargs basename -a
i xargs -n1 basename
. (Ze względu na porównanie typu „tak jak z podobnym” podane tutaj czasy są po początkowym manekinie, więc oba są wykonywane po skopiowaniu metadanych pliku do pamięci podręcznej we / wy.) Przesłałem dane wyjściowe do cksum
w obu przypadkach tylko w celu wykazania, że dane wyjściowe są niezależne od zastosowanej metody.
$ time sh -c 'find /usr/lib -type f -print0 | xargs -0 basename -a | cksum'
2532163462 546663
real 0m0.063s
user 0m0.058s
sys 0m0.040s
$ time sh -c 'find /usr/lib -type f -print0 | xargs -0 -n 1 basename | cksum'
2532163462 546663
real 0m14.504s
user 0m12.474s
sys 0m3.109s
Jak widać, naprawdę jest znacznie szybsze, aby uniknąć uruchamiania za basename
każdym razem.
basename
akceptuje wiele nazw plików bez potrzeby stosowania dodatkowych argumentów wiersza polecenia. Wykorzystanie -a
tutaj jest w systemie Linux. ( basename --version
mówi mi basename (GNU coreutils) 8.28
.)