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
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 comandied
sono goffi; i primi due comandi possono essere ridotti a%s/^/ /
e%j
.
<file xargs -L 1 -I{} command --option {} other args