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ż -iregexjest to rozszerzenie GNU do POSIXfind ) -regexi -iregexdomyślnie używasz wyrażeń regularnych Emacsa, które nie rozpoznają {3,}. Musisz określić inny typ wyrażeń regularnych za pomocą -regextypeopcji; 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 -Ejest 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 findimplementacjami (te, które obsługują -regexrównież obsługują -iname):
find ~ -iname '*???.pdf'
W przypadku dowolnej liczby znaków zamiast 3tego możesz wrócić do miejsca, w -iregexktórym jest dostępny (patrz odpowiedź @ Stephen Kitt ) lub możesz użyć zshlub ksh93globs:
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 zshró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 ksh93odpowiednikiem wyrażenia regularnego z{x,y}.~(i:...): dopasowanie bez rozróżniania wielkości liter.Globs mają findtutaj dodatkowe zalety , ponieważ otrzymujesz posortowaną listę (możesz wyłączyć to sortowanie zshza pomocą oNkwalifikatora 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, findpodejście nie zgłasza a $'St\xE9phane Chazelas - CV.pdf, \xE9ponieważ 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 .pdfw ich nazwach . Tylko dlatego, że plik zawiera znaki .pdfw 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, -inamemoż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ą filepolecenia. Jedna opcja generuje typ MIME , który jest łatwiejszy do przeanalizowania. findZapytania 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 ai 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ć updatedbdo zbudowania indeksu plików z możliwością przeszukiwania locatezamiast finddo odczytu tego indeksu i parallelzamiast tworzenia xargswą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.
.pdftwoim, 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).