Como passar cada linha de um arquivo de texto como um argumento para um comando?

33

Eu estou olhando para escrever um script que leva um .txt nome do arquivo como um argumento, lê o arquivo linha por linha e passa cada linha para um comando. Por exemplo, ele executa command --option "LINE 1" , depois command --option "LINE 2" , etc. A saída do comando é gravada em outro arquivo. Como faço para fazer isso? Não sei por onde começar.

    
por WojciechF 11.08.2014 / 19:06

6 respostas

24

Use while read loop:

: > another_file  ## Truncate file.

while read -r LINE; do
    command --option "$LINE" >> another_file
done < file

Outra é redirecionar a saída por bloco:

while read -r LINE; do
    command --option "$LINE"
done < file > another_file

Por último, é para abrir o arquivo:

exec 4> another_file

while read -r LINE; do
    command --option "$LINE" >&4
    echo xyz  ## Another optional command that sends output to stdout.
done < file

Se um dos comandos ler entrada, seria uma boa ideia usar outro fd para entrada, para que os comandos não o comam (aqui assumindo ksh , zsh ou bash para -u 3 , use <&3 em vez de portável):

while read -ru 3 LINE; do
    ...
done 3< file

Finalmente, para aceitar argumentos, você pode fazer:

#!/bin/bash

FILE=$1
ANOTHER_FILE=$2

exec 4> "$ANOTHER_FILE"

while read -ru 3 LINE; do
    command --option "$LINE" >&4
done 3< "$FILE"

Qual deles poderia ser executado como:

bash script.sh file another_file

Ideia extra. Com bash , use readarray :

readarray -t LINES < "$FILE"
for LINE in "${LINES[@]}"; do
    ...
done

Observação: não é necessário redefinir o valor de IFS (ou seja, IFS= read ) quando usar apenas um único parâmetro.

    
por 11.08.2014 / 19:09
24

Outra opção é xargs .

Com o GNU xargs :

< file xargs -I{} -d'\n' command --option {} other args

{} é o espaço reservado para a linha de texto.

Outros xargs não têm -d , mas alguns têm -0 para entrada delimitada por NUL. Com esses, você pode fazer:

< file tr '\n' '
< file sed 's/"/"\""/g;s/.*/"&"/' |
  xargs -E '' -I{} command --option {} other args
' | xargs -0 -I{} command --option {} other args

Em sistemas compatíveis com Unix ( -I é opcional em POSIX e necessário apenas para sistemas compatíveis com Unix), você precisaria pré-processar a entrada para citar as linhas no formato esperado por xargs :

< file xargs -I{} -d'\n' command --option {} other args

No entanto, observe que algumas implementações de xargs têm um limite muito baixo no tamanho máximo do argumento (255 no Solaris, por exemplo, o mínimo permitido pela especificação do Unix).

    
por 11.08.2014 / 19:24
6

Mantendo-se precisamente na questão:

#!/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
    
por 04.09.2016 / 14:11
3

A melhor resposta que encontrei é:

for i in 'cat'; do $cmd $i; done < $file
    
por 07.06.2015 / 06:53
2
    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
    
por 12.08.2014 / 00:35
-2
ed file.txt
%g/^/s// /
2,$g/^/-,.j
1s/^/command/
wq
chmod 755 file.txt
./file.txt

Pegue todas as linhas de um arquivo e passe-as como argumentos para um único comando, ou seja,

command line1 line2 line3 ....

Se você precisar que o sinal --option preceda cada linha, altere o segundo comando para:

%g/^/s// --option /
    
por 24.11.2014 / 05:50