Analizar un archivo de texto delimitado en bash como argumentos de comando

10

Tengo un archivo de texto dividido así:

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

Cada una de estas columnas será un parámetro para un programa, y ​​me gustaría que se llame al programa para cada línea

Esperaba un bucle, algo así como:

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

¿Cuál sería la mejor manera de lograr algo como esto en bash?

Decano
fuente
¿El número de campos es constante?
Joseph R.
@JosephR. sí lo son, siempre 3
Dean

Respuestas:

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

Esto debería funcionar si el número de campos es constante. En lugar de echousar tu comando.

taza de cafe
fuente
Gracias, solo estaba intentando esto, pero solo parece funcionar para la primera línea. Tan pronto como un comando tiene éxito, no prueba el siguiente, si falla, intentará el siguiente ...
Dean
¿Qué quieres decir con éxito o fracaso? ¿Qué hace tu comando?
coffeMug
Supongo que el comando que está ejecutando está leyendo la entrada estándar antes de que el comando "leer" pueda acceder.
plugwash
4

Debe usar a whilecon el readincorporado:

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

  • La cutinstrucción toma la línea y la divide en el delimitador especificado por -d.
  • El --output-delimiteres el carácter separador que cutse usará para mostrar los campos seleccionados, aquí elegimos un espacio para que podamos colocar los diferentes campos en la matriz fields.
  • Finalmente, queremos todos los campos (desde el campo 1 hasta el final) y ahí es donde -f1-entra en juego.
  • Ahora que tiene los diferentes campos almacenados en la variable de matriz fields, puede acceder a cualquier campo particular que desee con la sintaxis ${field[number]}donde numberes uno menos que el número de campo real que desea, ya que la indexación de matriz está basada en cero en Bash.

Nota

  • Esto fallará si alguno de sus campos contiene espacios en blanco.

Para un número constante de campos

En su lugar, puede hacer algo similar a la respuesta de 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

Lo anterior, aunque parece más ruidoso, debería funcionar en cualquier shell compatible con POSIX, no solo Bash.

Joseph R.
fuente
No tengo problemas para leer el archivo, está dividiendo la línea en columnas.
Dean
@ Dean Sí, lo siento. No estaba prestando atención. Trabajando en eso ahora.
Joseph R.
@Dean Por favor, vea la respuesta actualizada. Agregaré una explicación en breve.
Joseph R.
@JosephR., Es posible evitar el uso de herramientas externas para la división estableciendo IFSun valor apropiado en la readinvocación
iruvar
@ 1_CR Lo sé, gracias. Estaba llegando a eso :)
Joseph R.
1

Puede readdividir cada línea en una matriz ,activando IFSadecuadamente.

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

Entonces, en el ejemplo anterior, puede acceder a cada elemento de la matriz utilizando su índice, comenzando por 0.

iruvar
fuente
1

Este awkone-liner hará lo que quieras:

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

Reemplace echocon su comando y f.txtcon el archivo que desea recorrer.

Breve explicación: -F,se establecerá ,como delimitador. cmdconstruye el comando y system(cmd)llama al comando.

mkc
fuente
1

GNU SED también se puede utilizar.

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

observe el uso de la opción e para el comando s

hildred
fuente