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?


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.


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.


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.


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


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

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.