Vorrei trovare i file PDF il cui nome (esclusa l'estensione) è maggiore di tre.
$ find ~ -iregex ".{3,}/.pdf"
non restituisce nulla, ma
$ find ~ -iregex ".+/.pdf"
lavori.
Come posso abilitare la {3,}
variante?
Vorrei trovare i file PDF il cui nome (esclusa l'estensione) è maggiore di tre.
$ find ~ -iregex ".{3,}/.pdf"
non restituisce nulla, ma
$ find ~ -iregex ".+/.pdf"
lavori.
Come posso abilitare la {3,}
variante?
Risposte:
Supponendo che tu stia usando GNU find
(cosa che probabilmente sei, dal momento che -iregex
è un'estensione GNU a POSIXfind
), -regex
e di -iregex
default le espressioni regolari di Emacs, che non riconoscono {3,}
. È necessario specificare un diverso tipo di espressioni regolari utilizzando l' -regextype
opzione; inoltre, devi adattare la tua espressione regolare al fatto che l'espressione corrisponde al percorso completo:
find ~ -regextype posix-extended -iregex '.*/[^/]{3,}.pdf'
Dovresti anche sfuggire a in .
modo che corrisponda a "." piuttosto che qualsiasi personaggio:
find ~ -regextype posix-extended -iregex '.*/[^/]{3,}\.pdf'
L'espressione regolare può essere semplificata poiché ci preoccupiamo solo di tre caratteri non "/":
find ~ -regextype posix-extended -iregex '.*[^/]{3}\.pdf'
Per completezza, con FreeBSD o NetBSD find
(un'altra implementazione che supporta -iregex
, non la tua anche se .+
non funzionerebbe lì senza -E
), dovresti scrivere:
find ~ -iregex '.*[^/]\{3\}\.pdf'
o:
find -E ~ -iregex '.*[^/]{3}\.pdf'
Senza -E
, questa è un'espressione regolare di base (come in grep
) e con -E
un'espressione regolare estesa (come in grep -E
).
Con ast-open find
:
find ~ -iregex '.*[^/]{3}\.pdf'
(che è esteso regexps out of the box).
Qui è più facile con i caratteri jolly standard:
find ~ -name '*???.[pP][dD][fF]'
O con alcune find
implementazioni (anche quelle che supportano -regex
supportano -iname
):
find ~ -iname '*???.pdf'
Per un numero arbitrario di caratteri anziché 3
, è qui che potresti preferire tornare a -iregex
dove disponibile (vedi la risposta di @Stephen Kitt ) o potresti usare zsh
o ksh93
globs:
zsh
:
set -o extendedglob # best in ~/.zshrc
printf '%s\n' ~/**/?(#c3,).(#i)pdf(D)
(il (D)
da considerare file nascosti e file in directory nascoste come con find
)
(#cx,y)
è l' zsh
equivalente jolly di regexp{x,y}
(#i)
per maiuscole e minuscole?
carattere jolly standard per ogni singolo carattere (come regexp .
)**/
: qualsiasi livello di sottodirectory (incluso 0)ksh93
:
FIGNORE='@(.|..)' # to consider hidden files
set -o globstar
printf '%s\n' **/{3,}(?).~(i:pdf)
@(x|y)
: operatore jolly esteso ksh simile a regexp (x|y)
.FIGNORE
: variabile speciale che controlla quali file vengono ignorati dai globs. Se impostato, la normale ignorazione dei file nascosti non viene eseguita, ma vogliamo comunque ignorare le voci di directory .
e ..
dove presenti.{x,y}(z)
è ksh93
l'equivalente di regexp z{x,y}
.~(i:...)
: corrispondenza senza distinzione tra maiuscole e minuscole.I globi hanno alcuni vantaggi extra find
qui in quanto si ottiene un elenco ordinato (è possibile disabilitare tale ordinamento zsh
con il oN
qualificatore glob o utilizzare diversi criteri di ordinamento) e funziona anche quando i nomi dei file contengono una sequenza di byte che non formano caratteri validi (per ad esempio, in una locale che utilizza il set di caratteri UTF-8, l' find
approccio non riuscirebbe a riportare un $'St\xE9phane Chazelas - CV.pdf
dato che \xE9
non essendo un carattere non corrisponde a regexp .
o jolly ?
o *
con GNU find
).
shopt -s dotglob globstar; printf '%s\n' ~/**/*???.[pP][dD][fF]
Non lo fai a meno che non lo chieda. Certo, sono pedante, ma non hai chiesto informazioni sui file con i .pdf
loro nomi . Solo perché un file ha i caratteri .pdf
nel nome file non lo rende un file PDF .
In effetti, siamo completamente pedanti su questo: se gli ultimi quattro caratteri del nome di un file sono .pdf
, allora avrà sempre più di tre caratteri nel suo nome .
Quindi facendo questo nel modo sbagliato , potresti dire:
$ find . -type f -name "*???.pdf"
./Documents/McLaren 720s Coupe:Order Summary.pdf
./Documents/Setup_MagicISO.exe.pdf
Vedi quella seconda? In realtà è un eseguibile. (Lo so, ho cambiato il nome.) E mi manca anche un PDF che avrei potuto giurare fosse nella directory Documents ...
$ ls Documents
McLaren 720s Coupe:Order Summary.pdf
Pioneer Premier DEH-P490IB CD Install Manual.PDF
Setup_MagicISO.exe.pdf
Quindi usando -iname
questo potremmo trovare quello, ma questo sta ancora alzando questo file non PDF.
Quello che vogliamo veramente fare in questo caso è esaminare il numero magico del file usando il file
comando. Un'opzione genera il tipo MIME , che è più semplice da analizzare. La find
query diventa quindi semplice -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
Usiamo il delimitatore dei due punti e cerchiamo il tipo MIME application/pdf
, quindi azzeriamo quella parte e stampiamo il risultato. Prendi nota, uno dei miei file ha due punti nel nome; quindi non posso semplicemente chiedere a Awk di farlo ($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
Ora finiamo con l'idea di includere file PDF denominati a
e 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
È tutto. So che probabilmente sarò offeso per essere orribilmente pedante, ma nel mio lavoro con migliaia di volumi NFS da cacciare e tutti i tipi di file scarsamente nominati, vorrei che più persone fossero pedanti.
Modificato per aggiungere: nel mondo reale, potrei voler usare updatedb
per costruire un indice di file ricercabile, locate
invece di find
leggere quell'indice, e parallel
invece di xargs
fare il thread up. Questo è in qualche modo al di fuori dell'ambito di questa domanda. L'ho scritto anche con una faccia seria. Perché mi interessa così tanto? Potrei cercare film e file audio; o alcuni tipi di fotografie; o eseguibili binari in una directory di dati di progetto.
.pdf
, allora la tua pedanteria sarà molto apprezzata. Ma è una situazione relativamente insolita (nonostante il tuo lavoro) e non abbiamo alcun motivo per credere che il richiedente in realtà debba occuparsene, quindi penso che il punto che stai sollevando, seppur valido, sia fonte di distrazione - e penso che il modo in cui hai espresso la frase spinga la risposta nel regno di "(probabilmente) non utile". (Solo la mia opinione, ovviamente.)