Come analizzare ogni riga di un file di testo come argomento di un comando?

Sto cercando di scrivere uno script che prenda un .txt nome di file come argomento, legga la riga del file per riga e passa ogni riga a un comando. Ad esempio, esegue command --option "LINE 1", quindi command --option "LINE 2" e così via. Loutput del comando viene scritto in un altro file. Come posso farlo? Non so da dove iniziare.

Risposta

Utilizza il while read loop:

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

Un altro è reindirizzare loutput per blocco:

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

Lultimo è aprire il file:

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 uno dei comandi legge linput, sarebbe un buon idea di usare un altro fd per linput in modo che i comandi non lo mangino (qui assumendo ksh, zsh o bash per -u 3, utilizza <&3 invece portabile):

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

Fin alleato per accettare argomenti, puoi fare:

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

Quale potrebbe essere eseguito come:

bash script.sh file another_file 

Idea extra. Con bash, utilizza readarray:

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

Nota: IFS= può essere omesso se non ti dispiace che i valori di riga vengano tagliati dagli spazi iniziali e finali.

Risposta

Unaltra opzione è xargs.

Con GNU xargs:

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

{} è il segnaposto per la riga di testo.

Altro xargs generalmente non” t hanno -a, -d, ma alcuni hanno -0 per input delimitato da NUL. Con quelli, puoi fare:

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

Su sistemi conformi a Unix (-I è opzionale in POSIX e solo richiesto per i sistemi conformi a UNIX), devi preelaborare linput per citare le righe nel formato previsto da xargs:

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

Tuttavia, tieni presente che alcune xargs implementazioni hanno un limite molto basso sulla dimensione massima dellargomento (255 su Solaris, ad esempio, il minimo consentito dalla specifica Unix).

Commenti

  • riducibile a <file xargs -L 1 -I{} command --option {} other args
  • @iruvar, no, questo elaborerebbe le virgolette e rimuoverebbe alcuni spazi vuoti.

Risposta

Mantenendo la precisione alla domanda:

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

Commenti

  • ha funzionato come un fascino 🙂
  • +1 mi è piaciuto molto, grazie

Risposta

La migliore risposta che ho trovato und è:

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

EDIT:

… quattro anni dopo …

dopo diversi voti negativi e un po di esperienza in più, ti consiglio quanto segue ora:

xargs -l COMMAND < file 

Commenti

  • Questo richiamerà il comando una volta per ogni parola nel file. Inoltre, dovresti sempre citare i riferimenti alle variabili di shell (come in do "$cmd" "$i";) a meno che tu non abbia un motivo per non farlo; se il file conteneva un * come parola da solo, il codice verrebbe eseguito $cmd *, che, ovviamente, eseguirà il comando con un elenco dei file nella directory corrente.
  • @ G-Man, tranne in zsh, `cat` espanderebbe già il * (il $i non quotato potrebbe ancora espandere un carattere jolly (un secondo round) se lespansione di `cat` ne introduce alcuni). In ogni caso, questo approccio è davvero sbagliato.
  • +1. Funzionerà bene, se ogni riga contiene solo linput necessario per il comando utilizzato senza spazi.
  • +1, è piaciuta la soluzione xargs
  • Funziona! (la modifica successiva xargs -l COMMAND < file). Grazie!

Risposta

 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 

OUTPUT

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

Risposta

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

Prendi tutte le righe di un file e passarle come argomenti a un singolo comando, ad esempio

command line1 line2 line3 .... 

Se è necessario --option flag per precedere ogni riga modificare il secondo comando in:

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

Commenti

  • What -1 for usando ed … davvero?
  • Non ‘ ti ho votato in modo negativo, ma la persona che lha fatto aveva probabilmente questi motivi: (1) Questo non funziona cosa chiede la domanda. Questo richiama il comando una volta con tutto il contenuto del file sulla riga di comando; anziché una volta per riga .(2) Questo non fa nulla per gestire i caratteri che sono speciali per la shell (che potrebbero essere nel file); ad es. ', ", <, >, ;, ecc. (3) Questo crea un file temporaneo non necessario. (4) Cose come questa vengono generalmente fatte con i “documenti qui”. (5) I tuoi comandi ed sono goffi; i primi due comandi possono essere ridotti a %s/^/ / e %j.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *