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

Estou procurando escrever um script que tenha um .txt nome de arquivo como argumento, leia a linha do arquivo 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 está gravado em outro arquivo. Como faço para fazer isso? Não sei por onde começar.

Resposta

Use while read loop:

: > another_file ## Truncate file. while IFS= read -r LINE; do command --option "$LINE" >> another_file done < file 

Outra é redirecionar a saída por bloco:

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

Por último é abrir o arquivo:

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 

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

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

Fin aliado para aceitar argumentos, você pode fazer:

#!/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" 

Qual deles poderia ser executado como:

bash script.sh file another_file 

Idéia extra. Com bash, use readarray:

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

Observação: IFS= pode ser omitido se você não se importar em ter os valores das linhas cortados de espaços à esquerda e à direita.

Resposta

Outra opção é xargs.

Com GNU xargs:

xargs -a file -I{} -d"\n" command --option {} other args 

{} é o marcador de posição para a linha de texto.

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

< file tr "\n" "\0" | xargs -0 -I{} command --option {} other args 

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

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

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

Comentários

  • redutíveis a <file xargs -L 1 -I{} command --option {} other args
  • @iruvar, não, isso processaria aspas e removeria alguns espaços em branco.

Resposta

Manter a precisão à pergunta:

#!/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 

Comentários

  • funcionou como charme 🙂
  • +1 adorei, obrigado

Resposta

A melhor resposta que tenho para und is:

for i in `cat`; do "$cmd" "$i"; done < $file 

EDITAR:

… quatro anos depois …

depois de vários votos negativos e mais alguma experiência, eu recomendaria o seguinte agora:

xargs -l COMMAND < file 

Comentários

  • Isso irá invocar o comando uma vez para cada palavra no arquivo. Além disso, você deve sempre citar referências a variáveis de shell (como em do "$cmd" "$i";), a menos que tenha um motivo para não fazê-lo; se o arquivo contivesse um * como uma palavra por si só, seu código executaria $cmd *, que, claro, executaria o comando uma lista dos arquivos no diretório atual.
  • @ G-Man, exceto em zsh, o `cat` já expandiria o * (o $i não citado ainda poderia expandir algum curinga (uma segunda rodada) se a expansão de `cat` apresenta alguns). Em qualquer caso, essa abordagem está realmente errada.
  • +1. Isso funcionará bem, se cada linha contiver apenas a entrada necessária para o comando sendo usado sem espaços.
  • +1, solução xargs gostei
  • Isso está funcionando! (a edição posterior xargs -l COMMAND < file). Obrigado!

Resposta

 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 

SAÍDA

--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 

Resposta

ed file.txt %g/^/s// / 2,$g/^/-,.j 1s/^/command/ wq chmod 755 file.txt ./file.txt 

Pegue todos os linhas de um arquivo e passá-los como argumentos para um único comando, ou seja,

command line1 line2 line3 .... 

Se você precisar do --option sinalize para preceder cada linha, altere o segundo comando para:

%g/^/s// --option / 

Comentários

  • Para quê -1 usando ed … sério?
  • Eu não ‘ não votei contra você, mas a pessoa que o fez provavelmente teve estes motivos: (1) Isso não funciona o que a pergunta pede. Isso invoca o comando uma vez com todo o conteúdo do arquivo na linha de comando; em vez de uma vez por linha .(2) Isso não faz nada para lidar com caracteres que são especiais para o shell (que podem estar no arquivo); por exemplo, ', ", <, >, ;, etc. (3) Isso cria um arquivo temporário desnecessário. (4) Coisas como essa geralmente são feitas com “aqui documentos”. (5) Seus ed comandos são desajeitados; os dois primeiros comandos podem ser reduzidos a %s/^/ / e %j.

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *