Je souhaite retrouver les fichiers PDF dont le nom (hors extension) est supérieur à trois.
$ find ~ -iregex ".{3,}/.pdf"
ne renvoie rien, mais
$ find ~ -iregex ".+/.pdf"
travaux.
Comment puis-je activer la {3,}
variante?
Je souhaite retrouver les fichiers PDF dont le nom (hors extension) est supérieur à trois.
$ find ~ -iregex ".{3,}/.pdf"
ne renvoie rien, mais
$ find ~ -iregex ".+/.pdf"
travaux.
Comment puis-je activer la {3,}
variante?
Réponses:
En supposant que vous utilisez GNU find
(ce que vous êtes probablement, car -iregex
c'est une extension GNU pour POSIXfind
), -regex
et -iregex
par défaut pour les expressions régulières Emacs, qui ne reconnaissent pas {3,}
. Vous devez spécifier un type différent d'expressions régulières à l'aide de l' -regextype
option; en outre, vous devez ajuster votre expression régulière au fait que l'expression correspond au chemin complet:
find ~ -regextype posix-extended -iregex '.*/[^/]{3,}.pdf'
Vous devez également échapper au .
afin qu'il corresponde à "." plutôt que n'importe quel caractère:
find ~ -regextype posix-extended -iregex '.*/[^/]{3,}\.pdf'
L'expression régulière peut être simplifiée car nous ne nous soucions que de trois caractères non «/»:
find ~ -regextype posix-extended -iregex '.*[^/]{3}\.pdf'
Pour être complet, avec FreeBSD ou NetBSD find
(une autre implémentation qui prend en charge -iregex
, pas la vôtre, car .+
cela ne fonctionnerait pas sans -E
), vous écririez:
find ~ -iregex '.*[^/]\{3\}\.pdf'
ou:
find -E ~ -iregex '.*[^/]{3}\.pdf'
Sans -E
, c'est une expression régulière de base (comme dans grep
) et avec -E
une expression régulière étendue (comme dans grep -E
).
Avec ast-open find
:
find ~ -iregex '.*[^/]{3}\.pdf'
(c'est regexps étendu hors de la boîte).
Ici, c'est plus facile avec les caractères génériques standard:
find ~ -name '*???.[pP][dD][fF]'
Ou avec certaines find
implémentations (celles qui prennent en -regex
charge prennent également en charge -iname
):
find ~ -iname '*???.pdf'
Pour des nombres arbitraires de caractères au lieu de 3
, c'est là que vous préférerez peut-être revenir à l' -iregex
endroit où ils sont disponibles (voir la réponse de @Stephen Kitt ) ou vous pouvez utiliser zsh
ou ksh93
globs:
zsh
:
set -o extendedglob # best in ~/.zshrc
printf '%s\n' ~/**/?(#c3,).(#i)pdf(D)
(le (D)
pour considérer les fichiers cachés et les fichiers dans des répertoires cachés comme avec find
)
(#cx,y)
est l' zsh
équivalent générique de l'expression rationnelle{x,y}
(#i)
insensible à la casse?
caractère générique standard pour tout caractère unique (comme l'expression régulière .
)**/
: tout niveau de sous-répertoires (dont 0)ksh93
:
FIGNORE='@(.|..)' # to consider hidden files
set -o globstar
printf '%s\n' **/{3,}(?).~(i:pdf)
@(x|y)
: opérateur générique ksh étendu similaire à l'expression rationnelle (x|y)
.FIGNORE
: variable spéciale qui contrôle quels fichiers sont ignorés par les globes. Lorsqu'il est défini, l'ignorance habituelle des fichiers cachés n'est pas effectuée, mais nous voulons toujours ignorer les entrées du répertoire .
et ..
là où elles sont présentes.{x,y}(z)
est ksh93
l'équivalent de regexp z{x,y}
.~(i:...)
: correspondance insensible à la casse.Les globes ont quelques avantages supplémentaires find
ici dans la mesure où vous obtenez une liste triée (vous pouvez désactiver ce tri zsh
avec le oN
qualificatif glob ou utiliser différents critères de tri) et également fonctionner lorsque les noms de fichiers contiennent une séquence d'octets qui ne forment pas de caractères valides (pour Par exemple, dans un environnement local utilisant le jeu de caractères UTF-8, l' find
approche échouerait à signaler un $'St\xE9phane Chazelas - CV.pdf
car ce \xE9
n'est pas un caractère qui ne correspond pas à l'expression rationnelle .
ou au caractère générique ?
ou *
à GNU find
).
shopt -s dotglob globstar; printf '%s\n' ~/**/*???.[pP][dD][fF]
Vous ne le faites pas sauf si vous le demandez. Bien sûr, je suis pédant, mais vous n'avez pas posé de questions sur les fichiers avec .pdf
leur nom . Le fait qu'un fichier ait des caractères .pdf
dans le nom de fichier n'en fait pas un fichier PDF .
En fait, soyons pédant à ce sujet: si les quatre derniers caractères du nom d'un fichier le sont .pdf
, il aura toujours plus de trois caractères dans son nom .
Donc, en faisant cela dans le mauvais sens , vous pourriez dire:
$ find . -type f -name "*???.pdf"
./Documents/McLaren 720s Coupe:Order Summary.pdf
./Documents/Setup_MagicISO.exe.pdf
Vous voyez ce deuxième? C'est en fait un exécutable. (Je sais, j'ai changé le nom.) Et il me manque aussi un PDF que je pourrais jurer être dans le répertoire Documents ...
$ ls Documents
McLaren 720s Coupe:Order Summary.pdf
Pioneer Premier DEH-P490IB CD Install Manual.PDF
Setup_MagicISO.exe.pdf
Donc, en utilisant, -iname
nous pourrions trouver celui-là, mais cela continue de générer ce fichier non PDF.
Ce que nous voulons vraiment faire dans ce cas, c'est examiner le nombre magique du fichier à l' aide de la file
commande. Une option génère le type MIME , qui est plus simple à analyser. La find
requête devient alors simple -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
Utilisons le délimiteur deux-points, recherchons le type MIME application/pdf
, puis remettons à zéro cette partie et imprimons le résultat. Prenez note, un de mes fichiers a un deux-points dans le nom; donc je ne peux pas demander à 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
Terminons maintenant en essayant d'inclure les fichiers PDF nommés a
et 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
C'est tout. Je sais que je serai probablement fatigué d'être horriblement pédant, mais dans mon travail avec des milliers de volumes NFS à chasser et toutes sortes de fichiers mal nommés, je souhaite que plus de gens soient pédants.
Modifié pour ajouter: dans le monde réel, je pourrais vouloir utiliser updatedb
pour construire un index de fichier consultable, locate
au lieu de find
lire cet index, et parallel
au lieu de l' xargs
enfiler. C'est quelque peu en dehors de la portée de cette question. J'ai aussi écrit ça avec un visage impassible. Pourquoi je m'en soucie autant? Je recherche peut-être des films et des fichiers audio; ou certains types de photographies; ou exécutables binaires dans un répertoire de données de projet.
.pdf
, alors votre pédanterie sera très appréciée. Mais c'est une situation relativement inhabituelle (malgré votre travail) et nous n'avons aucune raison de croire que le demandeur doit réellement y faire face, donc je pense que l'argument que vous faites, bien que valide, est un peu distrayant - et je pense que la façon énergique que vous avez formulée pousse la réponse dans le domaine du "(probablement) pas utile". (Mon opinion seulement, bien sûr.)