Je cherche à écrire un script qui prend un .txt
filename comme argument, lit le fichier ligne par ligne et passe chaque ligne à une commande. Par exemple, il exécute command --option "LINE 1"
, puis command --option "LINE 2"
, etc. La sortie de la commande est écrite dans un autre fichier. Comment dois-je procéder? Je ne sais pas où commencer.
Utilisation while read
boucle:
: > another_file ## Truncate file.
while IFS= read -r LINE; do
command --option "$LINE" >> another_file
done < file
Une autre consiste à rediriger la sortie par bloc:
while IFS= read -r LINE; do
command --option "$LINE"
done < file > another_file
La dernière consiste à ouvrir le fichier:
exec 4> another_file
while IFS= read -r LINE; do
command --option "$LINE" >&4
echo xyz ## Another optional command that sends output to stdout.
done < file
Si l'une des commandes lit l'entrée, ce serait une bonne idée d'utiliser un autre fd pour l'entrée afin que les commandes ne le mangent pas (en supposant ici ksh
, zsh
ou bash
pour -u 3
, utilisation <&3
à la place de manière portable):
while IFS= read -ru 3 LINE; do
...
done 3< file
Enfin pour accepter les arguments, vous pouvez faire:
#!/bin/bash
FILE=$1
ANOTHER_FILE=$2
exec 4> "$ANOTHER_FILE"
while IFS= read -ru 3 LINE; do
command --option "$LINE" >&4
done 3< "$FILE"
Lequel pourrait fonctionner comme:
bash script.sh file another_file
Idée supplémentaire. Avec bash
, utilisez readarray
:
readarray -t LINES < "$FILE"
for LINE in "${LINES[@]}"; do
...
done
Remarque: IFS=
peut être omis si cela ne vous dérange pas de supprimer les valeurs de ligne des espaces de début et de fin.
Une autre option est xargs
.
Avec GNU xargs
:
< file xargs -I{} -d'\n' command --option {} other args
{}
est l'espace réservé pour la ligne de texte.
Les autres xargs
n'ont pas -d
, mais certains ont -0
pour une entrée délimitée par NUL. Avec ceux-ci, vous pouvez faire:
< file tr '\n' '\0' | xargs -0 -I{} command --option {} other args
Sur les systèmes conformes à Unix (-I
est facultatif dans POSIX et n'est requis que pour les systèmes conformes à Unix), vous devez prétraiter l'entrée pour quote les lignes au format attendu par xargs
:
< file sed 's/"/"\\""/g;s/.*/"&"/' |
xargs -E '' -I{} command --option {} other args
Notez cependant que certaines implémentations de xargs
ont une très faible limite sur la taille maximale de l'argument (255 sur Solaris par exemple, le minimum autorisé par la spécification Unix).
En restant précisément à la question:
#!/bin/bash
# xargs -n param sets how many lines from the input to send to the command
# Call command once per line
[[ -f $1 ]] && cat $1 | xargs -n1 command --option
# Call command with 2 lines as args, such as an openvpn password file
# [[ -f $1 ]] && cat $1 | xargs -n2 command --option
# Call command with all lines as args
# [[ -f $1 ]] && cat $1 | xargs command --option
La meilleure réponse que j'ai trouvée est:
for i in `cat`; do "$cmd" "$i"; done < $file
ÉDITER:
... quatre ans plus tard ...
après plusieurs votes négatifs et un peu plus d'expérience, je recommanderais maintenant ce qui suit
xargs -l COMMAND < file
sed "s/'/'\\\\''/g;s/.*/\$* '&'/" <<\FILE |\
sh -s -- command echo --option
all of the{&}se li$n\es 'are safely Shell
quoted and handed to command as its last argument
following --option, and, here, before that echo
FILE
--option all of the{&}se li$n\es 'are safely Shell
--option quoted and handed to command as its last argument
--option following --option, and, here, before that echo