Analisando um arquivo de texto delimitado no bash como argumentos de comando

10

Eu tenho um arquivo de texto dividido assim:

field1,field2,field3 
xield1,xield2,xield3 
dield1,dield2,dield3 
gield1,gield2,gield3

Cada uma dessas colunas será um parâmetro para um programa e eu gostaria que o programa fosse chamado para cada linha

Eu estava esperando por um loop, algo como:

for $i in file
    command $field2 -x $field3 -PN -$field1 >> output
done

Qual seria a melhor maneira de realizar algo assim no bash?

reitor
fonte
O número de campos é constante?
Joseph R.
@JosephR. sim, eles são, sempre 3 #
560 Dean Dean

Respostas:

7
while IFS=, read xx yy zz;do
    echo $xx $yy $zz
done < input_file

Isso deve funcionar se o número de campos for constante. Em vez de echousar seu comando.

coffeMug
fonte
Obrigado, eu estava apenas tentando isso, mas parece funcionar apenas para a primeira linha. Assim que um comando tiver êxito não tente o próximo, se não ele vai tentar o próximo embora ...
Dean
Como você entende por sucesso ou fracasso? Qual é o seu comando?
coffemug
Eu acho que o comando que ele está executando está lendo a entrada padrão antes que o comando "read" possa chegar lá.
Plugwash 24/05
4

Você deve usar um whilecom o readbuilt-in:

while IFS= read -r line;do
    fields=($(printf "%s" "$line"|cut -d',' --output-delimiter=' ' -f1-))
    command "${fields[1]}" -x "${fields[2]}" ... # ${fields[1]} is field 2
done < your_file_here

Como isso funciona

  • A cutinstrução pega a linha e a divide no delimitador especificado por -d.
  • O --output-delimiteré o caractere separador que cutserá usado para exibir os campos selecionados, aqui escolhemos um espaço para que possamos colocar os diferentes campos na matriz fields.
  • Finalmente, queremos todos os campos (do campo 1 ao final) e é aí que -f1-entra em jogo.
  • Agora que você tem os diferentes campos armazenados na variável da matriz fields, é possível acessar qualquer campo específico desejado com a sintaxe em ${field[number]}que numberseja um a menos que o número do campo real desejado, pois a indexação da matriz é baseada em zero no Bash.

Nota

  • Isso falhará se algum dos seus campos contiver espaço em branco.

Para um número constante de campos

Em vez disso, você pode fazer algo semelhante à resposta do 1_CR :

while IFS= read -r line;do
    IFS=, read -r field1 field2 field3 <<-EOI
    $line
    EOI
    command "$field2" -x "$field3" ... 
done < your_file_here

O acima, embora pareça mais barulhento, deve funcionar em qualquer shell compatível com POSIX, não apenas no Bash.

Joseph R.
fonte
Não está lendo o arquivo com o qual tenho problemas, está dividindo a linha em colunas.
Dean
@ Dean Sim, desculpe. Eu não estava prestando atenção. Trabalhando nisso agora.
Joseph R.
@ Dean Por favor, veja a resposta atualizada. Vou adicionar uma explicação em breve.
Joseph R.
@JosephR., É possível evitar o uso de ferramentas externas para a divisão definindo IFSum valor apropriado na readinvocação
iruvar
@ 1_CR Eu sei, obrigado. Eu estava apenas começando a isso :)
Joseph R.
1

Você pode readdividir cada linha em uma matriz ,configurando IFSadequadamente.

while IFS=, read -r -a input; do
 printf "%s\n" "${input[0]}" "${input[1]}"
done < input.txt

Portanto, no exemplo acima, você pode acessar cada elemento da matriz usando seu índice, iniciando 0.

iruvar
fonte
1

Este awkone-liner fará o que você deseja:

awk -F, '{cmd="echo " $2 " -x " $3 " -PN " $1 ">> output";  system(cmd)}' f.txt

Substitua echopor seu comando e f.txtpelo arquivo que você deseja repetir.

Breve explicação: -F,será definido ,como delimitador. cmdcria o comando e system(cmd)chama o comando

mkc
fonte
1

o gnu sed também pode ser usado.

sed infile -e 's!^\([^,]*\),\([^,]*\),\([^,]*\)$!command \1 -x \2 -PN \3!e' >> output

observe o uso da opção e no comando s

hildred
fonte