web-dev-qa-db-fra.com

Comment utiliser> dans une commande xargs?

Je veux trouver une commande bash qui me permettra de grep chaque fichier d'un répertoire et d'écrire la sortie de ce grep dans un fichier séparé. J'aurais supposé faire quelque chose comme ça

ls -1 | xargs -I{} "grep ABC '{}' > '{}'.out"

mais, autant que je sache, xargs n'aime pas les guillemets. Cependant, si je supprime les guillemets doubles, la commande redirige la sortie de la commande complète vers un fichier unique appelé "{}".

Est-ce que quelqu'un connaît un moyen de faire cela en utilisant xargs? J'ai simplement utilisé ce scénario grep comme exemple pour illustrer mon problème avec xargs, de sorte que toute solution n'utilisant pas xargs ne me convient pas.

147
Jesse Shieh

Ne faites pas l'erreur de faire ceci:

sh -c "grep ABC {} > {}.out"

Cela va casser dans beaucoup de conditions, y compris les noms de fichiers funky et il est impossible de citer correctement. Votre {} doit toujours être un seul argument complètement séparé de la commande pour éviter les bogues d'injection de code. Ce que vous devez faire, c'est ceci:

xargs -I{} sh -c 'grep ABC "$1" > "$1.out"' -- {}

S'applique à xargs ainsi qu'à find.

En passant, n'utilisez jamais xargs sans le -0 option (sauf en cas d'utilisation interactive unique et très rare et contrôlée ne vous inquiétant pas pour la destruction de vos données).

Aussi, ne pas analyser ls. Déjà. Utilisez globbing ou find à la place: http://mywiki.wooledge.org/ParsingLs

Utilisez find pour tout ce qui nécessite de la récursivité et une simple boucle avec un glob pour tout le reste:

find /foo -exec sh -c 'grep "$1" > "$1.out"' -- {} \;

ou non récursif:

for file in *; do grep "$file" > "$file.out"; done

Notez l'utilisation appropriée des guillemets.

181
lhunath

Une solution sans xargs est la suivante:

find . -mindepth 1 -maxdepth 1 -type f -exec sh -c "grep ABC '{}' > '{}.out'" \;

... et la même chose peut être faite avec xargs, il s'avère:

ls -1 | xargs -I {} sh -c "grep ABC '{}' > '{}.out'"

Modifier : guillemets simples ajoutés après remarque par lhunath .

39
Stephan202

Je suppose que votre exemple n'est qu'un exemple et que vous pourriez avoir besoin> d'autres choses. GNU Parallel http://www.gnu.org/software/parallel/ peut être votre sauvetage. Il n'a pas besoin de citations supplémentaires tant que vos noms de fichiers ne le sont pas. contient\n:

ls | parallel "grep ABC {} > {}.out"

Si vous avez des noms de fichiers avec\n dedans:

find . -print0 | parallel -0 "grep ABC {} > {}.out"

En prime, les travaux sont exécutés en parallèle.

Modifier.

Vous pouvez installer GNU Parallèle simplement en:

wget http://git.savannah.gnu.org/cgit/parallel.git/plain/src/parallel
chmod 755 parallel

Regardez les vidéos d'introduction pour en savoir plus: http://pi.dk/1

10 secondes d'installation:

wget pi.dk/3 -qO - | sh -x
14
Ole Tange