J'ai une entrée source, input.txt
a.txt
b.txt
c.txt
Je veux alimenter ces entrées dans un programme comme suit:
my-program --file=a.txt --file=b.txt --file=c.txt
J'essaie donc d'utiliser xargs , mais sans succès.
cat input.txt | xargs -i echo "my-program --file"{}
Il donne
my-program --file=a.txt
my-program --file=b.txt
my-program --file=c.txt
Mais je veux
my-program --file=a.txt --file=b.txt --file=c.txt
Une idée?
Aucune des solutions proposées jusqu'ici ne traite correctement les noms de fichiers contenant de l'espace. Certains échouent même si les noms de fichiers contiennent 'ou ". Si vos fichiers d'entrée sont générés par les utilisateurs, vous devriez être préparé à des noms de fichiers surprenants.
GNU Parallel traite bien ces noms de fichiers et vous donne (au moins) 3 solutions différentes. Si votre programme prend 3 et seulement 3 arguments, cela fonctionnera:
(echo a1.txt; echo b1.txt; echo c1.txt;
echo a2.txt; echo b2.txt; echo c2.txt;) |
parallel -N 3 my-program --file={1} --file={2} --file={3}
Ou:
(echo a1.txt; echo b1.txt; echo c1.txt;
echo a2.txt; echo b2.txt; echo c2.txt;) |
parallel -X -N 3 my-program --file={}
Si, toutefois, votre programme prend autant d'arguments que la ligne de commande en tiendra compte:
(echo a1.txt; echo b1.txt; echo c1.txt;
echo d1.txt; echo e1.txt; echo f1.txt;) |
parallel -X my-program --file={}
Regardez la vidéo d'introduction pour en savoir plus: http://www.youtube.com/watch?v=OpaiGYxkSuQ
ne les écoutez pas tous :) regardez juste cet exemple:
echo argument1 argument2 argument3 | xargs -l bash -c 'echo this is first:$0 second:$1 third:$2' | xargs
la sortie sera
this is first:argument1 second:argument2 third:argument3
Que diriez-vous:
echo $'a.txt\nb.txt\nc.txt' | xargs -n 3 sh -c '
echo my-program --file="$1" --file="$2" --file="$3"
' argv0
Vous pouvez utiliser sed
pour préfixer --file=
à chaque ligne, puis appeler xargs
:
sed -e 's/^/--file=/' input.txt | xargs my-program
Voici une solution utilisant sed pour trois arguments, mais limitée en ce sens qu'elle applique la même transformation à chaque argument:
cat input.txt | sed 's/^/--file=/g' | xargs -n3 my-program
Voici une méthode qui fonctionnera pour deux arguments, mais permet plus de flexibilité:
cat input.txt | xargs -n 2 | xargs -I{} sh -c 'V="{}"; my-program -file=${V% *} -file=${V#* }'
Je suis tombé sur un problème similaire et ai trouvé une solution qui, à mon avis, est meilleure et plus propre que celles présentées jusqu'à présent.
La syntaxe pour xargs
que j'ai terminée serait (par exemple):
xargs -I X echo --file=X
avec une ligne de commande complète étant:
my-program $(cat input.txt | xargs -I X echo --file=X)
qui fonctionnera comme si
my-program --file=a.txt --file=b.txt --file=c.txt
a été fait (à condition que input.txt
contienne les données de votre exemple).
En fait, dans mon cas, je devais d'abord trouver les fichiers, puis les trier afin que ma ligne de commande ressemble à ceci:
my-program $(find base/path -name "some*pattern" -print0 | sort -z | xargs -0 -I X echo --files=X)
Quelques détails qui pourraient ne pas être clairs (ils n'étaient pas pour moi):
some*pattern
doit être cité, sinon Shell le développerait avant de passer à find
.-print0
, puis -z
et enfin -0
utilisent une séparation nulle pour garantir le traitement correct des fichiers avec des espaces ou d'autres noms câblés.Notez cependant que je ne l'ai pas encore testé profondément. Bien que cela semble fonctionner.
Je cherchais une solution à ce problème précis et suis parvenu à la conclusion de coder un script dans le midle.
pour transformer la sortie standard de l'exemple suivant, utilisez le séparateur -n '\ n'
exemple:
user@mybox:~$ echo "file1.txt file2.txt" | xargs -n1 ScriptInTheMiddle.sh
inside the ScriptInTheMidle.sh:
!#/bin/bash
var1=`echo $1 | cut -d ' ' -f1 `
var2=`echo $1 | cut -d ' ' -f2 `
myprogram "--file1="$var1 "--file2="$var2
Pour que cette solution fonctionne, vous devez laisser un espace entre les arguments file1.txt et file2.txt, ou le délimiteur que vous choisissez, encore une fois, dans le script, assurez-vous de cocher -f1 et -f2 car ils signifient "prendre les premier mot et prenez le deuxième mot "en fonction de la position du premier séparateur trouvée (les délimètres peuvent être" ";" "." comme vous le souhaitez entre guillemets simples. Ajoutez autant de paramètres que vous le souhaitez.
Problème résolu en utilisant xargs, cut et quelques scripts bash.
À votre santé!
si vous voulez passer, j'ai quelques conseils utiles http://hongouru.blogspot.com
En fait, c'est relativement facile:
... | sed 's/^/--prefix=/g' | xargs echo | xargs -I PARAMS your_cmd PARAMS
Le sed 's/^/--prefix=/g'
est facultatif, au cas où vous auriez besoin de préfixer chaque paramètre avec un --prefix =.
Le xargs echo
transforme la liste des lignes de paramètres (un paramètre par ligne) en une liste de paramètres sur une seule ligne et le xargs -I PARAMS your_cmd PARAMS
vous permet d'exécuter une commande en plaçant les paramètres à l'endroit souhaité.
Donc, cat input.txt | sed 's/^/--file=/g' | xargs echo | xargs -I PARAMS my-program PARAMS
fait ce dont vous avez besoin (en supposant que toutes les lignes du fichier input.txt sont simples et peuvent être considérées comme une valeur param unique).
C'est parce que echo
imprime une nouvelle ligne. Essayez quelque chose comme
echo my-program `xargs --arg-file input.txt -i echo -n " --file "{}`
xargs ne fonctionne pas de cette façon. Essayer:
monprogramme $ (sed -e 's/^/- file = /' input.txt)
C'est plus simple si vous utilisez deux invocations xargs: 1ère pour transformer chaque ligne en --file=...
, 2ième pour faire la chose xargs ->
$ cat input.txt | xargs -I@ echo --file=@ | xargs echo my-program
my-program --file=a.txt --file=b.txt --file=c.txt
Personne n'a encore mentionné l'écho d'une boucle. Je vais donc en parler par souci de complétude (ce serait ma deuxième approche, le sed étant la première):
for line in $(< input.txt) ; do echo --file=$line ; done | xargs echo my-program