Analizzare un file di testo delimitato in bash come argomenti di comando


10

Ho un file di testo suddiviso in questo modo:

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

Ognuna di queste colonne sarà un parametro per un programma e vorrei che il programma fosse chiamato per ogni linea

Speravo in un loop, qualcosa del tipo:

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

Quale sarebbe il modo migliore per ottenere qualcosa del genere in bash?


Il numero di campi è costante?
Joseph R.,

@JosephR. si lo sono, sempre 3
Decano

Risposte:


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

Questo dovrebbe funzionare se il numero di campi è costante. Invece di echousare il tuo comando.


Grazie, stavo solo provando questo, ma sembra funzionare solo per la prima linea. Non appena un comando ha esito positivo, non prova il successivo, se fallisce tenterà anche il successivo ...
Decano

Come intendi successo o fallimento? Cosa fa il tuo comando?
coffeMug

Immagino che il comando che sta eseguendo stia leggendo l'input standard prima che il comando "read" riesca ad ottenerlo.
plugwash

4

Dovresti usare a whilecon il 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

Come funziona

  • L' cutistruzione prende la linea e la divide nel delimitatore specificato da -d.
  • Il --output-delimiterè il carattere separatore che cutuserà per visualizzare i campi selezionati, qui abbiamo scelto uno spazio in modo da poter inserire i vari campi nella matrice fields.
  • Infine, vogliamo tutti i campi (dal campo 1 alla fine) ed è qui che -f1-entra in gioco.
  • Ora hai i diversi campi memorizzati nella variabile array fields, puoi accedere a qualsiasi campo particolare che desideri con la sintassi ${field[number]}dove numberè uno in meno del numero di campo effettivo che desideri poiché l'indicizzazione dell'array è a base zero in Bash.

Nota

  • Ciò fallirà se uno dei tuoi campi contiene spazi bianchi.

Per un numero costante di campi

Puoi invece fare qualcosa di simile alla risposta di 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

Quanto sopra, sebbene sembri più rumoroso, dovrebbe funzionare in qualsiasi shell conforme a POSIX, non solo Bash.


Non sta leggendo il file con cui ho problemi, sta spezzando la linea in colonne.
Decano

@Dean Sì, scusa. Non stavo prestando attenzione. Ci sto lavorando adesso.
Joseph R.,

@ Decano Vedi la risposta aggiornata. Aggiungerò una spiegazione a breve.
Joseph R.,

. @JosephR, è possibile evitare l'utilizzo di strumenti esterni per la scissione impostando IFSad un valore appropriato nella readinvocazione
Iruvar

@ 1_CR Lo so, grazie. Ci stavo arrivando :)
Joseph R. il

1

È possibile readdividere ciascuna riga in un array ,impostando in modo IFSappropriato.

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

Quindi nell'esempio sopra, puoi accedere a ciascun elemento dell'array usando il suo indice, iniziando da 0.


1

Questo awkone-liner farà quello che vuoi:

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

Sostituisci echocon il tuo comando e f.txtcon il file che desideri scorrere.

Breve spiegazione: -F,verrà impostato ,come delimitatore. cmdcrea il comando e system(cmd)chiama il comando.


1

gnu sed può anche essere usato.

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

notate l'uso dell'opzione e al comando s

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.