Odpowiedzi:
W GNU findmożesz do tego użyć -printfparametru, np .:
find /dir1 -type f -printf "%f\n"
-oMa niższy priorytet niż sugerowany -a, więc często będziesz chciał pogrupować swoje -oargumenty)
Jeśli twoje wyszukiwanie nie ma opcji -printf, możesz także użyć basename:
find ./dir1 -type f -exec basename {} \;
... {} ';'
Użyj, -execdirktóra automatycznie przechowuje bieżący plik {}, na przykład:
find . -type f -execdir echo '{}' ';'
Możesz także użyć $PWDzamiast .(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 ...] ;
-execdirPodstawowy jest identyczny z-execpierwotnym 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.
./filenamezamiast filename. W zależności od potrzeb może być lub nie być w porządku.
$PWDzamiast ..
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 basenamemoż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ć xargswynik. 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 {} \;
-execi -execdirsą powolne, xargsjest 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
xargsRównoległość pomaga również.
Co zabawne, nie potrafię wyjaśnić ostatniego przypadku xargsbez -n1. Daje poprawny wynik i jest najszybszy¯\_(ツ)_/¯
( basenamepobiera tylko 1 argument ścieżki, ale xargswyś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 -execdirpomaga, 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
findjest to -execdir, że staje się najszybciej jak tworzenie nowych procesów jest stosunkowo kosztowna operacja.
Jak zauważyli inni, możesz łączyć findi basename, ale domyślnie basenameprogram 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 ... -execlub dwóch find ... | xargs -n 1), co może być potencjalnie wolne.
Jeśli użyjesz tej -aopcji basename, może zaakceptować wiele nazw plików w jednym wywołaniu, co oznacza, że możesz użyć xargsbez -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 -print0i -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 -ai 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 cksumw 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 basenamekażdym razem.
basenameakceptuje wiele nazw plików bez potrzeby stosowania dodatkowych argumentów wiersza polecenia. Wykorzystanie -atutaj jest w systemie Linux. ( basename --versionmówi mi basename (GNU coreutils) 8.28.)