J'ai toujours eu ce problème: j'ai un glob, qui correspond exactement aux bons fichiers, mais qui cause Command line too long
. Chaque fois que je l'ai converti en une combinaison de find
et grep
cela fonctionne pour la situation particulière, mais qui n'est pas 100% équivalent.
Par exemple:
./foo*bar/quux[A-Z]{.bak,}/pic[0-9][0-9][0-9][0-9]?.jpg
Existe-t-il un outil pour convertir des globes en find
expressions que je ne connais pas? Ou existe-t-il une option pour find
faire correspondre le glob sans faire correspondre le même glob dans un sous-répertoire (par exemple, foo/*.jpg
n'est pas autorisé à faire correspondre bar/foo/*.jpg
)?
-path
ou-ipath
.find . -path './foo*bar/quux[A-Z]/pic[0-9][0-9][0-9][0-9]?.jpg'
devrait fonctionner - sauf qu'il correspondra/fooz/blah/bar/quuxA/pic1234d.jpg
. Sera-ce un problème?echo <glob> | cat
, en supposant que ma connaissance de bash, echo estRéponses:
Si le problème est que vous obtenez une erreur argument-list-is-too-long, utilisez une boucle ou un shell intégré. Bien que l'
command glob-that-matches-too-much
erreur puisse survenir,for f in glob-that-matches-too-much
non, vous pouvez donc simplement faire:La boucle peut être atrocement lente, mais cela devrait fonctionner.
Ou:
(
printf
étant intégré dans la plupart des shells, ce qui précède contourne la limitation de l'execve()
appel système)Fonctionne également avec bash. Je ne sais pas exactement où cela est documenté.
Les deux Vim
glob2regpat()
et Pythonfnmatch.translate()
peuvent convertir des globes en expressions régulières, mais les deux utilisent également.*
pour*
, la correspondance entre/
.la source
something
parecho
devrait le faire.printf
- ce sera plus rapide que d'appeler desecho
milliers de fois et offre plus de flexibilité.exec
, qui s'applique aux commandes externes telles quecat
; mais cette limite ne s'applique pas aux commandes internes du shell telles queprintf
.printf
est intégrée, et les shells utilisent vraisemblablement la même méthode pour lui fournir des arguments qu'ils utilisent pour énumérer les argumentsfor
.cat
n'est pas une fonction intégrée.mksh
oùprintf
n'est pas intégré et des coquilles commeksh93
oùcat
est (ou peut être) intégré. Voir aussizargs
danszsh
pour contourner ce problème sans avoir à y recourirxargs
.find
(pour les prédicats-name
/-path
standard) utilise des modèles génériques comme les globs (notez que ce{a,b}
n'est pas un opérateur glob; après expansion, vous obtenez deux globs). La principale différence réside dans la gestion des barres obliques (et des fichiers de points et des répertoires qui ne sont pas traités spécialement dansfind
).*
dans globs ne s'étendra pas sur plusieurs répertoires.*/*/*
entraînera la liste de 2 niveaux de répertoires. L'ajout d'un-path './*/*/*'
correspondra à tous les fichiers qui ont au moins 3 niveaux de profondeur et ne s'arrêtera pasfind
de lister le contenu d'un répertoire à n'importe quelle profondeur.Pour ce particulier
quelques globes, c'est facile à traduire, vous voulez des répertoires en profondeur 3, donc vous pouvez utiliser:
(ou
-depth 3
avec certainesfind
implémentations). Ou POSIX:Ce qui garantirait que ceux-ci
*
et?
ne pourraient pas correspondre aux/
caractères.(
find
, contrairement à globs lirait le contenu de répertoires autres quefoo*bar
ceux du répertoire courant¹, et ne trierait pas la liste des fichiers. Mais si nous laissons de côté le problème de ce à quoi correspond[A-Z]
ou le comportement de*
/?
en ce qui concerne les caractères invalides non spécifié, vous obtiendrez la même liste de fichiers).Mais dans tous les cas, comme l' a montré @muru , il n'est pas nécessaire d'y recourir
find
s'il s'agit simplement de diviser la liste de fichiers en plusieurs exécutions pour contourner la limite de l'execve()
appel système. Certains shells commezsh
(aveczargs
) ouksh93
(aveccommand -x
) ont même un support intégré pour cela.Avec
zsh
(dont les globes ont également l'équivalent de-type f
et la plupart des autresfind
prédicats), par exemple:(
(|.bak)
est un opérateur glob contrairement à{,.bak}
, le(.)
qualificatif glob est l'équivalent defind
's'-type f
, ajoutez-oN
y pour ignorer le tri comme avecfind
,D
pour inclure les fichiers de points (ne s'applique pas à ce glob))¹ Pour
find
explorer l'arborescence de répertoires comme le feraient les globes, vous auriez besoin de quelque chose comme:C'est-à-dire élaguer tous les répertoires au niveau 1 à l'exception de
foo*bar
ceux et tous au niveau 2 à l'exception de ceuxquux[A-Z]
ouquux[A-Z].bak
, puis sélectionnerpic...
ceux au niveau 3 (et élaguer tous les répertoires à ce niveau).la source
Vous pouvez écrire une expression régulière pour trouver correspondant à vos besoins:
la source
.
, ajouter le match en option pour.bak
et le changement*
à la[^/]*
non - correspondance des chemins comme / foo / foo / bar , etc.[0-9][0-9][0-9][0-9]?
à[0-9]{3,4}
En généralisant la note de mon autre réponse , comme réponse plus directe à votre question, vous pouvez utiliser ce
sh
script POSIX pour convertir le glob en unefind
expression:Pour être utilisé avec un
sh
glob standard (donc pas les deux glob de votre exemple qui utilise l' expansion d'accolade ):(qui n'ignore pas les fichiers-point ou point-dirs sauf
.
et..
et ne trie pas la liste des fichiers).Celui-ci ne fonctionne qu'avec des globes par rapport au répertoire courant, sans
.
ou..
composants. Avec un peu d'effort, vous pouvez l'étendre à n'importe quel glob, plus qu'un glob ... Cela pourrait également être optimisé afin que la rechercheglob2find 'dir/*'
ne soit pasdir
la même que celle d'un modèle.la source