Disons que j'ai un tableau:
cat template > output
for var in "${ITEMS[@]}"; do
cat output | my_template $var > output
done
Je veux exécuter la commande suivante:
cat template \ | my_command $ITEMS[1] \ | my_command $ITEMS[2] \ | my_command $ITEMS[3] \ > output
Je ne veux pas trop coder le ma_commande pour chaque élément du tableau, car le tableau est dynamique.
Je peux faire ce qui suit:
ITEMS=( "foo" "bar" "baz" )
Mais cela semble maladroit car il écrit plusieurs fois dans le fichier.
Existe-t-il un moyen d'obtenir toutes les invocations de ma_commande dans la même commande, quand il y a un nombre inconnu d'invocations?
3 Réponses :
Voici un moyen d'utiliser printf et le très décrié eval:
eval $(printf 'cat template '; printf '| my_command "%s" ' "${ITEMS[@]}") > output
Utilisez-le uniquement lorsque vous êtes sûr qu'il y a aucune entrée malveillante dans le tableau ITEMS .
Vous pouvez rediriger tout le bloc de boucle vers la sortie, donc:
my_template "foo" "bar" "baz" <template
Alternativement, si votre programme my_template peut accepter plusieurs éléments comme arguments, vous pouvez le transmettre tout le tableau en un seul appel avec:
my_template "${ITEMS[@]}" <template
Cela appellera:
for var in "${ITEMS[@]}"; do
my_template "${var}" <template
done >output
J'aime la première approche, et je pense que cela fonctionnera dans mon cas, mais est-ce que cela fonctionnerait si (hypothétiquement) chaque appel de my_command dépendait de la sortie précédente?
Non, chaque appel traite le template indépendamment des autres.
@FelaMaslen vous pourriez probablement enchaîner l'entrée et la sortie dans la boucle en utilisant un tube nommé: mypipe = $ (mktemp -u); mkfifo -m 600 "$ {mypipe}"; pour var dans "$ {ITEMS [@]}"; do my_template "$ {var}" <"$ {mypipe}" >> "$ {mypipe}"; Fini; cat "$ {mypipe}"> sortie; rm "$ {mypipe}"
Utilisez une bonne récursion à l'ancienne.
1) ), exécutez la commande directement. *) ), exécutez-le avec le premier argument ( $ {args [0]} ) et dirigez-le vers un appel récursif de multipipe avec le premier argument supprimé ( $ {args [@]: 1} ). multipipe() {
local cmd=$1
local args=("${@:2}")
case ${#args[@]} in
0) ;;
1) "$cmd" "${args[0]}";;
*) "$cmd" "${args[0]}" | multipipe "$cmd" "${args[@]:1}";;
esac
}
multipipe my_command "${ITEMS[@]}" <template >output
C'est la solution la plus claire et ne dépend pas de eval . +1
my_commandn'accepte-t-il qu'un seul paramètre d'entrée? Ou pourriez-vous réécriremy_commandpour accepter plusieurs valeurs?ma_commandeest un programme externe que je n'ai pas écrit, alors disons qu'il doit être au format fourni.