Je « cherche à écrire un script qui prend un nom de fichier .txt
comme argument, lit la ligne du fichier par ligne et transmet chaque ligne à une commande. Par exemple, elle exécute command --option "LINE 1"
, puis command --option "LINE 2"
, etc. La sortie de la commande est écrit dans un autre fichier. Comment dois-je procéder? Je ne sais pas par où commencer.
Réponse
Utilisez la boucle while read
:
: > 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
Le dernier est douvrir 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 lune des commandes lit lentrée, ce serait un bon idée dutiliser un autre fd pour lentrée pour que les commandes ne le mangent pas (ici en supposant ksh
, zsh
ou bash
pour -u 3
, utilisez <&3
à la place de manière portable):
while IFS= read -ru 3 LINE; do ... done 3< file
Aileron allié 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 couper les valeurs de ligne des espaces de début et de fin.
Réponse
Une autre option est xargs
.
Avec GNU xargs
:
xargs -a file -I{} -d"\n" command --option {} other args
{}
est lespace réservé pour la ligne de texte.
Autre xargs
nont généralement pas -a
, -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 uniquement requis pour les systèmes conformes à UNIX), vous devez prétraiter l’entrée pour citer 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 limite très basse sur la taille maximale de largument (255 sur Solaris par exemple, le minimum autorisé par la spécification Unix).
Commentaires
Réponse
Garder 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
Commentaires
- a fonctionné comme un charme 🙂
- +1 adoré, merci
Réponse
La meilleure réponse que jai pour und est:
for i in `cat`; do "$cmd" "$i"; done < $file
EDIT:
… quatre ans plus tard …
après plusieurs votes négatifs et un peu plus dexpérience, je « recommanderais ce qui suit maintenant:
xargs -l COMMAND < file
Commentaires
- Cela invoquera la commande une fois pour chaque word du fichier. De plus, vous devriez toujours citer les références aux variables shell (comme dans
do "$cmd" "$i";
) sauf si vous avez une raison de ne pas le faire; si le fichier contenait un*
en tant que mot à lui seul, votre code exécuterait$cmd *
, ce qui, bien sûr, exécuterait la commande avec une liste des fichiers dans le répertoire courant. - @ G-Man, sauf dans
zsh
, le`cat`
développerait déjà le*
(le$i
sans guillemets pourrait encore développer un caractère générique (un deuxième tour) si lexpansion de`cat`
en introduit). Dans tous les cas, cette approche est en effet erronée. - +1. Cela fonctionnera très bien, si chaque ligne ne contient que lentrée nécessaire à la commande utilisée sans espaces.
- +1, a aimé la solution xargs
- Cela fonctionne! (la dernière modification
xargs -l COMMAND < file
). Merci!
Réponse
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
OUTPUT
--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
Réponse
ed file.txt %g/^/s// / 2,$g/^/-,.j 1s/^/command/ wq chmod 755 file.txt ./file.txt
Prenez toutes les lignes dun fichier et passez-les comme arguments à une seule commande, cest-à-dire
command line1 line2 line3 ....
Si vous avez besoin de --option
indicateur pour précéder chaque ligne, remplacez la deuxième commande par:
%g/^/s// --option /
Commentaires
- Quest-ce que -1 pour en utilisant ed … vraiment?
- Je ne vous ‘ t contre vous, mais la personne qui l’a fait a probablement eu les raisons suivantes: (1) Ce n’est pas le cas ce que demande la question. Cela appelle la commande une fois avec tout le contenu du fichier sur la ligne de commande; plutôt que une fois par ligne .(2) Cela ne fait rien pour gérer les caractères qui sont spéciaux pour le shell (qui pourraient être dans le fichier); par exemple,
'
,"
,<
,>
,;
, etc. (3) Cela crée un fichier temporaire inutile. (4) Des choses comme celles-ci se font généralement avec des «documents ici». (5) Vos commandesed
sont maladroites; les deux premières commandes peuvent être réduites à%s/^/ /
et%j
.
<file xargs -L 1 -I{} command --option {} other args