Estoy buscando escribir un script que tome un .txt
nombre de archivo como argumento, lee la línea del archivo por línea y pasa cada línea a un comando. Por ejemplo, ejecuta command --option "LINE 1"
, luego command --option "LINE 2"
, etc. La salida del comando está escrito en otro archivo. ¿Cómo puedo hacerlo? No sé por dónde empezar.
Respuesta
Use while read
bucle:
: > another_file ## Truncate file. while IFS= read -r LINE; do command --option "$LINE" >> another_file done < file
Otra es redirigir la salida por bloque:
while IFS= read -r LINE; do command --option "$LINE" done < file > another_file
Lo último es abrir el archivo:
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 uno de los comandos lee input, sería bueno idea de usar otro fd para la entrada para que los comandos «no se lo coman (aquí asumiendo ksh
, zsh
o bash
para -u 3
, use <&3
en su lugar portátil):
while IFS= read -ru 3 LINE; do ... done 3< file
Aleta Aliado para aceptar argumentos, puede hacer:
#!/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"
Cuál podría ejecutarse como:
bash script.sh file another_file
Idea adicional. Con bash
, use readarray
:
readarray -t LINES < "$FILE" for LINE in "${LINES[@]}"; do ... done
Nota: IFS=
se puede omitir si no le importa que los valores de línea se eliminen de los espacios iniciales y finales.
Respuesta
Otra opción es xargs
.
Con GNU xargs
:
xargs -a file -I{} -d"\n" command --option {} other args
{}
es el marcador de posición para la línea de texto.
Otro xargs
generalmente no» tienen -a
, -d
, pero algunos tienen -0
para entrada delimitada por NUL. Con ellos, puede hacer:
< file tr "\n" "\0" | xargs -0 -I{} command --option {} other args
En sistemas compatibles con Unix (-I
es opcional en POSIX y solo requerido para los sistemas que cumplen con UNIX), necesitará preprocesar la entrada para citar las líneas en el formato esperado por xargs
:
< file sed "s/"/"\\""/g;s/.*/"&"/" | xargs -E "" -I{} command --option {} other args
Sin embargo, tenga en cuenta que algunas xargs
implementaciones tienen un límite muy bajo en el tamaño máximo del argumento (255 en Solaris, por ejemplo, el mínimo permitido por la especificación de Unix).
Comentarios
Responder
Mantener la precisión a la pregunta:
#!/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
Comentarios
- funcionó a la perfección 🙂
- +1 me encantó esto, gracias
Responder
La mejor respuesta para und es:
for i in `cat`; do "$cmd" "$i"; done < $file
EDITAR:
… cuatro años después …
después de varios votos negativos y algo más de experiencia, recomendaría lo siguiente ahora:
xargs -l COMMAND < file
Comentarios
- Esto invocará el comando una vez por cada word en el archivo. Además, siempre debe citar referencias a variables de shell (como en
do "$cmd" "$i";
) a menos que tenga una razón para no hacerlo; si el archivo contiene un*
como una palabra por sí mismo, su código ejecutará$cmd *
, que, por supuesto, ejecutará el comando con una lista de los archivos en el directorio actual. - @ G-Man, excepto en
zsh
, el`cat`
ya expandiría el*
(el$i
sin comillas aún podría expandir algún comodín (una segunda ronda) si la expansión de`cat`
presenta algunos). En cualquier caso, ese enfoque es incorrecto. - +1. Esto funcionará bien, si cada línea contiene solo la entrada necesaria para el comando que se usa sin espacios.
- +1, me gustó la solución xargs
- ¡Esto está funcionando! (la edición posterior
xargs -l COMMAND < file
). ¡Gracias!
Respuesta
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
SALIDA
--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
Responder
ed file.txt %g/^/s// / 2,$g/^/-,.j 1s/^/command/ wq chmod 755 file.txt ./file.txt
Tome todas las líneas de un archivo y pasarlas como argumentos a un solo comando, es decir,
command line1 line2 line3 ....
Si necesita --option
bandera para preceder cada línea cambie el segundo comando a:
%g/^/s// --option /
Comentarios
- ¿Para qué -1 usando ed … ¿de verdad?
- Yo no ‘ t voté en contra de ti, pero la persona que lo hizo probablemente tuvo estas razones: (1) Esto no lo que pide la pregunta. Esto invoca el comando una vez con todo el contenido del archivo en la línea de comando; en lugar de una vez por línea .(2) Esto no hace nada para manejar caracteres que son especiales para el shell (que podrían estar en el archivo); Por ejemplo,
'
,"
,<
,>
,;
, etc. (3) Esto crea un archivo temporal innecesario. (4) Cosas como esta generalmente se hacen con «aquí documentos». (5) Tused
comandos son torpes; los dos primeros comandos se pueden reducir a%s/^/ /
y%j
.
<file xargs -L 1 -I{} command --option {} other args