J'essaie de copier un tas de fichiers sous un répertoire et un certain nombre de fichiers ont des espaces et des guillemets simples dans leurs noms. Lorsque j'essaie de chaîner ensemble find
et grep
avec xargs
, j'obtiens l'erreur suivante:
find .|grep "FooBar"|xargs -I{} cp "{}" ~/foo/bar
xargs: unterminated quote
Des suggestions pour une utilisation plus robuste de xargs?
C'est sur Mac OS X 10.5.3 (Leopard) avec BSD xargs
.
--delimiter
option (-d
). Essayez-le avec\n
comme délimiteur, cela empêchexargs
de séparer les lignes avec des espaces en plusieurs mots / arguments.Réponses:
Vous pouvez combiner tout cela en une seule
find
commande:Cela gérera les noms de fichiers et les répertoires contenant des espaces. Vous pouvez utiliser
-name
pour obtenir des résultats sensibles à la casse.Remarque: l'
--
indicateur transmis à l'cp
empêche de traiter les fichiers commençant par-
comme options.la source
xargs
n'est pas nécessaire pour résoudre le problème que vous décrivez, lefind
supporte déjà avec la-exec
+
ponctuation.find . -print0 | grep --null 'FooBar' | xargs -0 ...
Je ne sais pas si
grep
prend en charge--null
, ni sixargs
prend en charge-0
, sur Leopard, mais sur GNU c'est tout bon.la source
grep -{z|Z}
signifie "se comporter comme zgrep" (décompresser) et non pas le "imprimer un octet zéro après chaque nom de fichier". Utilisezgrep --null
pour atteindre ce dernier.find . -name 'FooBar' -print0 | xargs -0 ...
?-name
ou-path
fonctionne très bien. L'OP a spécifié l'utilisation degrep
, probablement parce qu'ils veulent filtrer la liste à l'aide d'expressions régulières.xargs -0
en conjonction avecfind -print0
. Ce dernier imprime les noms de fichiers avec un terminateur NUL et le premier reçoit les fichiers de cette façon. Pourquoi? Les noms de fichiers sous Unix peuvent contenir des caractères de nouvelle ligne. Mais ils ne peuvent pas contenir de caractères NUL.La façon la plus simple de faire ce que l'affiche originale veut est de changer le délimiteur de n'importe quel espace en juste le caractère de fin de ligne comme ceci:
la source
sed -e 's_\(.*\)_"\1"_g'
de citations de force autour du nom de fichierxargs
.xargs: illegal option -- d
C'est plus efficace car il ne lance pas "cp" plusieurs fois:
la source
J'ai rencontré le même problème. Voici comment je l'ai résolu:
J'avais l'habitude
sed
de remplacer chaque ligne d'entrée par la même ligne, mais entourée de guillemets doubles. À partir de lased
page de manuel, " ... Une esperluette (` `& '') apparaissant dans le remplacement est remplacée par la chaîne correspondant à RE ... " - dans ce cas.*
, la ligne entière.Cela résout l'
xargs: unterminated quote
erreur.la source
sed s/.*/\"&\"/
pour le faire fonctionner."
in - à moins que sed ne cite également des citations?sed
est géniale et pour l'instant la bonne solution sans réécrire le problème!Cette méthode fonctionne sur Mac OS X v10.7.5 (Lion):
J'ai également testé la syntaxe exacte que vous avez publiée. Cela a également bien fonctionné sur 10.7.5.
la source
-I
implique-L 1
(comme le dit le manuel), ce qui signifie que la commande cp est exécutée une fois par file = v slow.find ... -print0
etxargs -0
pour contourner les xargs «par défaut, les guillemets sont spéciaux». Deuxièmement, utilisez généralement les commandes'{}'
not{}
in passées à xargs pour vous protéger contre les espaces et les caractères spéciaux.Ne l'utilisez pas
xargs
. C'est un programme soigné mais ça ne va pas bien avecfind
cas non triviaux.Voici une solution portable (POSIX), c'est-à-dire qui ne nécessite pas
find
,xargs
oucp
des extensions spécifiques à GNU:Notez la fin
+
au lieu de la plus habituelle;
.Cette solution:
gère correctement les fichiers et les répertoires avec des espaces intégrés, des retours à la ligne ou tout autre caractère exotique.
fonctionne sur n'importe quel système Unix et Linux, même ceux qui ne fournissent pas la boîte à outils GNU.
n'utilise pas
xargs
ce qui est un programme agréable et utile, mais nécessite trop de réglages et de fonctionnalités non standard pour gérer correctement lafind
sortie.est également plus efficace (lire plus rapidement ) que les autres réponses acceptées et la plupart sinon toutes les autres.
Notez également que malgré ce qui est indiqué dans certaines autres réponses ou commentaires, la citation
{}
est inutile (sauf si vous utilisez lafish
coquille exotique ).la source
find
peut faire ce qui sexargs
passe sans frais généraux.Envisagez d'utiliser l'option de ligne de commande --null pour xargs avec l'option -print0 dans find.
la source
Pour ceux qui s'appuient sur des commandes, autres que trouver, par exemple
ls
:la source
-I
implique-L 1
Je crois que cela fonctionnera de manière fiable pour n'importe quel personnage, sauf le saut de ligne (et je soupçonne que si vous avez des sauts de ligne dans vos noms de fichiers, vous avez des problèmes plus graves que cela). Il ne nécessite pas de découverte GNU, juste Perl, donc il devrait fonctionner à peu près n'importe où.
la source
mkdir test && cd test && perl -e 'open $fh, ">", "this-file-contains-a-\n-here"' && ls | od -tx1
|perl -lne 'print quotemeta'
est exactement ce que je cherchais. D'autres articles ici ne m'ont pas aidé, car plutôt quefind
je devais utilisergrep -rl
pour réduire considérablement le nombre de fichiers PHP uniquement ceux infectés par des logiciels malveillants.J'ai trouvé que la syntaxe suivante fonctionne bien pour moi.
Dans cet exemple, je recherche les 200 fichiers les plus volumineux de plus de 1 000 000 octets dans le système de fichiers monté sur "/ usr / pcapps".
Le trait de ligne Perl entre "find" et "xargs" échappe / cite chaque blanc afin que "xargs" passe tout nom de fichier avec des blancs incorporés à "ls" comme un seul argument.
la source
Défi du cadre - vous demandez comment utiliser xargs. La réponse est: vous n'utilisez pas xargs, car vous n'en avez pas besoin.
Le commentaire de
user80168
décrit un moyen de le faire directement avec cp, sans appeler cp pour chaque fichier:Cela fonctionne parce que:
cp -t
indicateur permet de donner le répertoire cible vers le débutcp
plutôt que vers la fin. Deman cp
:Le
--
drapeau indiquecp
de tout interpréter après comme un nom de fichier, pas un drapeau, donc les fichiers commençant par-
ou--
ne confondent pascp
; vous en avez toujours besoin car les caractères-
/--
sont interprétés parcp
, tandis que tout autre caractère spécial est interprété par le shell.La
find -exec command {} +
variante fait essentiellement la même chose que xargs. Deman find
:En l'utilisant directement dans find, cela évite d'avoir besoin d'un tuyau ou d'une invocation de shell, de sorte que vous n'avez pas à vous soucier des caractères désagréables dans les noms de fichiers.
la source
Sachez que la plupart des options abordées dans d'autres réponses ne sont pas standard sur les plates-formes qui n'utilisent pas les utilitaires GNU (Solaris, AIX, HP-UX, par exemple). Voir le POSIX spécification pour le comportement xargs «standard».
Je trouve également que le comportement de xargs par lequel il exécute la commande au moins une fois, même sans entrée, est une nuisance.
J'ai écrit ma propre version privée de xargs (xargl) pour traiter les problèmes d'espaces dans les noms (seuls les retours à la ligne se séparent - bien que la combinaison 'find ... -print0' et 'xargs -0' soit assez nette étant donné que les noms de fichiers ne peuvent pas contiennent des caractères ASCII NUL '\ 0'. Mon xargl n'est pas aussi complet qu'il devrait en valoir la peine d'être publié - d'autant plus que GNU possède des fonctionnalités au moins aussi bonnes.
la source
find
n'a pas besoinxargs
en premier lieu (et c'était déjà vrai il y a 11 ans).Avec Bash (pas POSIX), vous pouvez utiliser la substitution de processus pour obtenir la ligne actuelle dans une variable. Cela vous permet d'utiliser des guillemets pour échapper les caractères spéciaux:
la source
Pour moi, j'essayais de faire quelque chose d'un peu différent. Je voulais copier mes fichiers .txt dans mon dossier tmp. Les noms de fichiers .txt contiennent des espaces et des caractères d'apostrophe. Cela a fonctionné sur mon Mac.
la source
Trouvez et si les versions xarg sur votre système ne prend pas en charge
-print0
et les-0
commutateurs (par exemple trouver AIX et xargs) vous pouvez utiliser ce code à la recherche terriblement:Ici sed prendra soin d'échapper aux espaces et aux guillemets pour xargs.
Testé sur AIX 5.3
la source
J'ai créé un petit script wrapper portable appelé "xargsL" autour de "xargs" qui résout la plupart des problèmes.
Contrairement à xargs, xargsL accepte un chemin d'accès par ligne. Les chemins d'accès peuvent contenir n'importe quel caractère sauf (évidemment) les sauts de ligne ou NUL.
Aucune citation n'est autorisée ou prise en charge dans la liste des fichiers - vos noms de fichiers peuvent contenir toutes sortes d'espaces blancs, de barres obliques inverses, de barres obliques inverses, de caractères génériques de shell et autres - xargsL les traitera comme des caractères littéraux, sans aucun dommage.
Comme bonus supplémentaire, xargsL n'exécutera pas la commande une fois s'il n'y a pas d'entrée!
Notez la différence:
Tous les arguments donnés à xargsL seront transmis à xargs.
Voici le script shell POSIX "xargsL":
Mettez le script dans un répertoire de votre $ PATH et n'oubliez pas de
$ chmod +x xargsL
le script là pour le rendre exécutable.
la source
La version Perl de bill_starr ne fonctionnera pas bien pour les sauts de ligne intégrés (ne fait face qu'aux espaces). Pour ceux sur Solaris par exemple où vous n'avez pas les outils GNU, une version plus complète pourrait être (en utilisant sed) ...
ajustez les arguments find et grep ou d'autres commandes selon vos besoins, mais le sed corrigera vos nouvelles lignes / espaces / tabulations intégrés.
la source
J'ai utilisé la réponse de Bill Star légèrement modifiée sur Solaris:
Cela mettra des guillemets autour de chaque ligne. Je n'ai pas utilisé l'option '-l' bien que cela aiderait probablement.
La liste de fichiers que j'allais peut-être pourrait avoir «-», mais pas de nouvelles lignes. Je n'ai pas utilisé le fichier de sortie avec d'autres commandes car je veux revoir ce qui a été trouvé avant de commencer à les supprimer massivement via xargs.
la source
J'ai joué un peu avec cela, j'ai commencé à envisager de modifier les xargs et j'ai réalisé que pour le type de cas d'utilisation dont nous parlons ici, une simple réimplémentation en Python est une meilleure idée.
D'une part, avoir ~ 80 lignes de code pour le tout signifie qu'il est facile de comprendre ce qui se passe, et si un comportement différent est requis, vous pouvez simplement le pirater dans un nouveau script en moins de temps qu'il n'en faut pour obtenir une réponse quelque part comme Stack Overflow.
Voir https://github.com/johnallsup/jda-misc-scripts/blob/master/yargs et https://github.com/johnallsup/jda-misc-scripts/blob/master/zargs.py .
Avec yargs tel qu'écrit (et Python 3 installé), vous pouvez taper:
pour copier 203 fichiers à la fois. (Ici, 203 n'est qu'un espace réservé, bien sûr, et l'utilisation d'un nombre étrange comme 203 indique clairement que ce nombre n'a pas d'autre signification.)
Si vous voulez vraiment quelque chose de plus rapide et sans avoir besoin de Python, prenez des zargs et des yargs comme prototypes et réécrivez en C ++ ou C.
la source
Vous devrez peut-être grep répertoire Foobar comme:
la source
-i
est obsolète et-I
doit être utilisé à la place.Si vous utilisez Bash, vous pouvez convertir stdout en un tableau de lignes en
mapfile
:Les avantages sont les suivants:
Vous pouvez ajouter d'autres arguments aux noms de fichiers. Pour
cp
, vous pouvez également:cependant, certaines commandes n'ont pas une telle fonctionnalité.
Les désavantages:
Eh bien ... qui sait si Bash est disponible sur OS X?
la source