Jak używać polecenia znajdź, aby wyświetlić nazwy plików, ale nie ścieżkę?
Sprawdziłem niektóre odpowiedzi online, ale nie działają, gdy -name
w poleceniu jest parametr (może robię coś źle, nie jestem pewien). To, co chciałbym zrobić, to wymienić tylko nazwy plików (nie katalog / ścieżkę), a żeby jeszcze bardziej skomplikować, mam tę samą nazwę pliku z innym rozszerzeniem, więc muszę przefiltrować wynik za pomocą -name
i -o
, problemem są sugestie, że ja widziałem użycie albo -printf
lub basename
, a te nie działają dobrze, gdy jest -name *.txt -o name *.pdf
. Czy istnieje inny sposób rozwiązania tego problemu?
Przykładowe moje pliki:
/dir1/dir2/dir3/dir4/
/file1.txt
/file1.pdf
/file1.ods ...etc.
Interesuje mnie tylko wystawianie jednego lub więcej typów plików na listę (używając -name
do filtrowania wyników.
Czy można to zrobić za pomocą tylko 1 find
polecenia, czy muszę to zrobić w 2 krokach (zapisanie wyniku w pliku tymczasowym, następnie przefiltrowanie / usunięcie katalogu z pliku tymczasowego)? Rezultatem, który próbuję osiągnąć, jest plik tekstowy z nazwą pliku w każdym wierszu:
file1.txt
file1.pdf
file1.ods
file2.txt
file2.pdf
etc.
Polecenie, którego użyłem, to
find /dir1/dir2/dir3/dir4/ -type f -name '*.txt' -o -name '*.pdf' -o -name '*.ods' -printf "%f\n"
Używam wyszukiwania GNU.
Aktualizacja
Okazało się, że muszę umieścić \(...\)
, o czym przypomniał αғsнιη
Odpowiedzi
Używając wielu wyrażeń w trybie logicznym OR -o
, musisz je wszystkie zamknąć wewnątrz \( ... \)
, w przeciwnym razie ostatni wynik wyrażenia jest zawsze uwzględniany; i -printf '%f\n'
służy do drukowania nazw plików tylko z usuniętymi wiodącymi katalogami.
find . -type f \( -name '*.pdf' -o -name '*.txt' \) -printf '%f\n'
patrz man findw sekcji OPERATORZY o ( expr )
:
OPERATORZY
...(wyrażenie)
Wymuś pierwszeństwo. Ponieważ nawiasy są specjalne dla powłoki, zwykle trzeba je zacytować.
więc możesz użyć \( ... \)
lub '(' ... ')'
(białe spacje po i przed nawiasami są ważne), aby je uciec.
Jak już wspomniano, -name
testy należy pogrupować w nawiasach. Te nawiasy muszą być chronione \( ... \)
lub cytowane jako np. '(' ... ')'
Aby chronić je przed powłoką (gdzie w innym przypadku oznaczałyby podpowłokę).
Używanie standardu find
, a także nieco łatwiejsza obsługa sufiksów nazw plików:
set -- txt pdf ods
for suffix do
set -- "$@" -o -name "*.$suffix"
shift
done
shift
find /dir1/dir2/dir3/dir4 \( "$@" \) -type f -exec basename {} \;
Najpierw ustawia parametry pozycyjne na liście przyrostków nazw plików, które chcielibyśmy zobaczyć (może to być również wzięte z wiersza poleceń, jeśli jest to skrypt) i tworzy listę OR -name
testów. Jest to następnie używane w find
linii poleceń.
Samo find
polecenie wywołuje następnie basename
narzędzie dla każdej znalezionej nazwy.
Alternatywnie moglibyśmy zamiast tego użyć substytucji parametrów, aby usunąć wszystkie składniki każdej ścieżki oprócz nazwy pliku, ale w tym celu musimy przekazać nazwy ścieżek do sh -c
skryptu wbudowanego :
# [...] as before [...]
find /dir1/dir2/dir3/dir4 \( "$@" \) -type f -exec sh -c '
for pathname do
printf "%s\n" "${pathname##*/}"
done' sh {} +
Spodziewałbym się, że będzie to działać szybciej niż wersja używająca basename
, przynajmniej jeśli jest wiele nazw plików do obsłużenia, chociaż w przypadku GNU basename
z coreutils możesz użyć -a
lub --multiple
polubić:
find /dir1/dir2/dir3/dir4 \( "$@" \) -type f -exec basename -a {} +
To zadzwoniłoby basename
tak kilka razy, jak to możliwe. Ale z drugiej strony, gdybyś miał zainstalowany coreutils, możesz mieć również findutils z GNU find
i mógłbyś użyć -printf '%f\n'
do tego samego.