Chciałbym znaleźć pliki PDF, których nazwa (bez rozszerzenia) jest większa niż trzy.
$ find ~ -iregex ".{3,}/.pdf"
nic nie zwraca, ale
$ find ~ -iregex ".+/.pdf"
Pracuje.
Jak mogę włączyć {3,}
wariant?
Chciałbym znaleźć pliki PDF, których nazwa (bez rozszerzenia) jest większa niż trzy.
$ find ~ -iregex ".{3,}/.pdf"
nic nie zwraca, ale
$ find ~ -iregex ".+/.pdf"
Pracuje.
Jak mogę włączyć {3,}
wariant?
Odpowiedzi:
Zakładając, że używasz GNU find
(którym prawdopodobnie jesteś, ponieważ -iregex
jest to rozszerzenie GNU do POSIXfind
) -regex
i -iregex
domyślnie używasz wyrażeń regularnych Emacsa, które nie rozpoznają {3,}
. Musisz określić inny typ wyrażeń regularnych za pomocą -regextype
opcji; ponadto musisz dostosować wyrażenie regularne do tego, aby wyrażenie pasowało do pełnej ścieżki:
find ~ -regextype posix-extended -iregex '.*/[^/]{3,}.pdf'
Powinieneś także uciec przed, .
aby pasował do „.” zamiast jakiejkolwiek postaci:
find ~ -regextype posix-extended -iregex '.*/[^/]{3,}\.pdf'
Wyrażenie regularne można uprościć, ponieważ obchodzą nas tylko trzy znaki inne niż „/”:
find ~ -regextype posix-extended -iregex '.*[^/]{3}\.pdf'
Dla kompletności, z FreeBSD lub NetBSD find
(inna implementacja, która obsługuje -iregex
, ale nie twoja, ponieważ .+
bez niej nie działałaby -E
), napiszesz:
find ~ -iregex '.*[^/]\{3\}\.pdf'
lub:
find -E ~ -iregex '.*[^/]{3}\.pdf'
Bez -E
jest to podstawowe wyrażenie regularne (jak w grep
) i -E
rozszerzone wyrażenie regularne (jak w grep -E
).
Z ast-open's find
:
find ~ -iregex '.*[^/]{3}\.pdf'
(to rozszerzone wyrażenia regularne po wyjęciu z pudełka).
Tutaj jest łatwiej dzięki standardowym symbolom wieloznacznym:
find ~ -name '*???.[pP][dD][fF]'
Lub z niektórymi find
implementacjami (te, które obsługują -regex
również obsługują -iname
):
find ~ -iname '*???.pdf'
W przypadku dowolnej liczby znaków zamiast 3
tego możesz wrócić do miejsca, w -iregex
którym jest dostępny (patrz odpowiedź @ Stephen Kitt ) lub możesz użyć zsh
lub ksh93
globs:
zsh
:
set -o extendedglob # best in ~/.zshrc
printf '%s\n' ~/**/?(#c3,).(#i)pdf(D)
( (D)
do rozważenia ukrytych plików i plików w ukrytych katalogach, takich jak z find
)
(#cx,y)
jest zsh
równoważnym wyrażeniem regularnym wyrażenia regularnego{x,y}
(#i)
dla bez rozróżniania wielkości liter?
standardowy symbol wieloznaczny dla dowolnego pojedynczego znaku (np. regexp .
)**/
: dowolny poziom podkatalogów (w tym 0)ksh93
:
FIGNORE='@(.|..)' # to consider hidden files
set -o globstar
printf '%s\n' **/{3,}(?).~(i:pdf)
@(x|y)
: rozszerzony operator symboli wieloznacznych ksh podobny do wyrażenia regularnego (x|y)
.FIGNORE
: specjalna zmienna, która kontroluje, które pliki są ignorowane przez globs. Po ustawieniu zwykłe ignorowanie ukrytych plików nie jest wykonywane, ale nadal chcemy ignorować wpisy katalogu .
i, ..
jeśli są obecne.{x,y}(z)
jest ksh93
odpowiednikiem wyrażenia regularnego z{x,y}
.~(i:...)
: dopasowanie bez rozróżniania wielkości liter.Globs mają find
tutaj dodatkowe zalety , ponieważ otrzymujesz posortowaną listę (możesz wyłączyć to sortowanie zsh
za pomocą oN
kwalifikatora glob lub użyć innych kryteriów sortowania), a także działać, gdy nazwy plików zawierają sekwencję bajtów, które nie tworzą prawidłowych znaków (dla instancja, w ustawieniach narodowych używających zestawu znaków UTF-8, find
podejście nie zgłasza a $'St\xE9phane Chazelas - CV.pdf
, \xE9
ponieważ nie jest to znak , który nie jest dopasowywany przez wyrażenie regularne, .
symbol wieloznaczny ?
lub *
GNU find
).
shopt -s dotglob globstar; printf '%s\n' ~/**/*???.[pP][dD][fF]
Nie, chyba że zapytasz. Jasne, jestem pedantyczny, ale nie pytałeś o pliki .pdf
w ich nazwach . Tylko dlatego, że plik zawiera znaki .pdf
w nazwie pliku , nie czyni go plikiem PDF .
W rzeczywistości bądźmy pedantyczni: jeśli cztery ostatnie znaki nazwy pliku to .pdf
, to zawsze będzie zawierać więcej niż trzy znaki w nazwie .
Więc robiąc to w niewłaściwy sposób , możesz powiedzieć:
$ find . -type f -name "*???.pdf"
./Documents/McLaren 720s Coupe:Order Summary.pdf
./Documents/Setup_MagicISO.exe.pdf
Widzisz ten drugi? W rzeczywistości jest to plik wykonywalny. (Wiem, zmieniłem nazwę). Brakuje też pliku PDF, który mógłbym przysiąc, że był w katalogu Dokumenty ...
$ ls Documents
McLaren 720s Coupe:Order Summary.pdf
Pioneer Premier DEH-P490IB CD Install Manual.PDF
Setup_MagicISO.exe.pdf
Używając tego, -iname
możemy go znaleźć, ale wciąż pojawia się ten plik inny niż PDF.
Tym, co naprawdę chcemy zrobić w tym przypadku, jest sprawdzenie magicznej liczby pliku za pomocą file
polecenia. Jedna opcja generuje typ MIME , który jest łatwiejszy do przeanalizowania. find
Zapytania staje się proste -name "???*"
.
$ find . -type f -name "???*" -print0|xargs -0 file --mime
./.bash_history: text/plain; charset=us-ascii
./.bash_logout: text/plain; charset=us-ascii
./.bashrc: text/plain; charset=us-ascii
./.profile: text/plain; charset=us-ascii
./Documents/McLaren 720s Coupe:Order Summary.pdf: application/pdf; charset=binary
./Documents/Pioneer Premier DEH-P490IB CD Install Manual.PDF: application/pdf; charset=binary
./Documents/Setup_MagicISO.exe.pdf: application/x-dosexec; charset=binary
./Downloads/Setup_MagicISO.exe: application/x-dosexec; charset=binary
./Downloads/WindowsUpdate.diagcab: application/vnd.ms-cab-compressed; charset=binary
Użyjmy separatora dwukropka i poszukaj typu MIME application/pdf
, a następnie wyzeruj tę część i wydrukuj wynik. Zauważ, że jeden z moich plików ma dwukropek w nazwie; więc nie mogę po prostu poprosić o awk ($2==":"){print $1}
.
$ find . -type f -name "???*" -print0|xargs -0 file --mime|awk -F: '($NF~"application/pdf"){OFS=":";$NF="";print}'|sed s/:$//
./Documents/McLaren 720s Coupe:Order Summary.pdf
./Documents/Pioneer Premier DEH-P490IB CD Install Manual.PDF
Teraz zakończmy, włączając w to pliki PDF o nazwach a
i abc
:
$ mkdir Documents/other
$ cp -a Documents/McLaren\ 720s\ Coupe\:Order\ Summary.pdf Documents/other/a
$ cp -a Documents/Pioneer\ Premier\ DEH-P490IB\ CD\ Install\ Manual.PDF Documents/other/abc
$ find . -type f -name "???*" -print0|xargs -0 file --mime|awk -F: '($NF~"application/pdf"){OFS=":";$NF="";print}'|sed s/:$//
./Documents/McLaren 720s Coupe:Order Summary.pdf
./Documents/Pioneer Premier DEH-P490IB CD Install Manual.PDF
./Documents/other/abc
To wszystko. Wiem, że prawdopodobnie zostanę obłąkany za okropnie pedantyczne, ale w mojej pracy z tysiącami woluminów NFS do polowania i wszelkiego rodzaju źle nazwanych plików, chciałbym, żeby więcej ludzi było pedantycznych.
Edytowane w celu dodania: w prawdziwym świecie mógłbym chcieć użyć updatedb
do zbudowania indeksu plików z możliwością przeszukiwania locate
zamiast find
do odczytu tego indeksu i parallel
zamiast tworzenia xargs
wątków. Jest to jednak nieco poza zakresem tego pytania. Napisałem to również z prostą twarzą. Dlaczego tak mnie to obchodzi? Być może szukam plików filmowych i dźwiękowych; lub niektóre rodzaje fotografii; lub binarne pliki wykonywalne w katalogu danych projektu.
.pdf
twoim, pedanteria będzie mile widziana. Ale jest to stosunkowo niezwykła sytuacja (pomimo twojej pracy) i nie mamy żadnego powodu, aby sądzić, że pytający faktycznie musi sobie z tym poradzić, więc uważam, że twoja uwaga, choć ważna, jest trochę rozpraszająca - i myślę, że silny sposób, w jaki to sformułowałeś, wypycha odpowiedź do dziedziny „(prawdopodobnie) nieprzydatnej”. (Oczywiście tylko moja opinia).