Jag vill skriva ett skript som tar ett .txt filnamn som argument, läser filraden för rad och skickar varje rad till ett kommando. Den kör till exempel command --option "LINE 1", sedan command --option "LINE 2", etc. Utdata från kommandot skrivs till en annan fil. Hur ska jag göra det? Jag vet inte var jag ska börja.
Svar
Använd while read loop:
: > another_file ## Truncate file. while IFS= read -r LINE; do command --option "$LINE" >> another_file done < file
Ett annat är att omdirigera utdata med block:
while IFS= read -r LINE; do command --option "$LINE" done < file > another_file
Det sista är att öppna filen:
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
Om ett av kommandona läser inmatning skulle det vara bra idé att använda en annan fd för inmatning så kommandona kommer inte att äta den (här förutsatt att ksh, zsh eller bash för -u 3, använd <&3 istället bärbart):
while IFS= read -ru 3 LINE; do ... done 3< file
Fin allierad för att acceptera argument kan du göra:
#!/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"
Vilken man kan köra som:
bash script.sh file another_file
Extra idé. Använd bash, använd readarray:
readarray -t LINES < "$FILE" for LINE in "${LINES[@]}"; do ... done
Obs: IFS= kan utelämnas om du inte tänker ha linjevärden trimmade av ledande och efterföljande mellanslag.
Svar
Ett annat alternativ är xargs.
Med GNU xargs:
xargs -a file -I{} -d"\n" command --option {} other args
{} är platshållaren för textraden.
Annat xargs har vanligtvis inte -a, -d, men vissa har -0 för NUL-avgränsad ingång. Med dessa kan du göra:
< file tr "\n" "\0" | xargs -0 -I{} command --option {} other args
På Unix-överensstämmande system (-I är valfritt i POSIX och endast krävs för UNIX-överensstämmande system), måste du förbehandla ingången för att citera raderna i det format som förväntas av xargs:
< file sed "s/"/"\\""/g;s/.*/"&"/" | xargs -E "" -I{} command --option {} other args
Observera dock att vissa xargs -implementeringar har en mycket låg gräns för argumentets maximala storlek (till exempel 255 på Solaris, det lägsta tillåtna enligt Unix-specifikationen).
Kommentarer
Svar
Att hålla exakt till frågan:
#!/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
Kommentarer
- fungerade som charm 🙂
- +1 älskade det här, tack
Svar
Det bästa svaret jag har und is:
for i in `cat`; do "$cmd" "$i"; done < $file
EDIT:
… fyra år senare …
efter flera nedröstningar och lite mer erfarenhet skulle jag rekommendera följande nu:
xargs -l COMMAND < file
Kommentarer
- Detta anropar kommandot en gång för varje ord i filen. Du bör också citera referenser till skalvariabler (som i
do "$cmd" "$i";) såvida du inte har en anledning att inte göra det; om filen innehöll en*som ett ord i sig, skulle din kod köras$cmd *, vilket naturligtvis skulle köra kommandot med en lista över filerna i den aktuella katalogen. - @ G-Man, utom i
zsh,`cat`skulle redan expandera*(det ociterade$ikan fortfarande utvidga ett jokertecken (en andra omgång) om expansionen av`cat`introducerar några). Hur som helst är den metoden verkligen fel. - +1. Detta kommer att fungera bra, om varje rad bara innehåller den ingång som behövs för att kommandot ska användas utan mellanslag.
- +1, gillade xargs-lösning
- Detta fungerar! (den senare redigeringen
xargs -l COMMAND < file). Tack!
Svar
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
UTGÅNG
--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
Svar
ed file.txt %g/^/s// / 2,$g/^/-,.j 1s/^/command/ wq chmod 755 file.txt ./file.txt
Ta alla rader i en fil och skicka dem som argument till ett enda kommando, dvs
command line1 line2 line3 ....
Om du behöver --option flagga före varje rad ändra det andra kommandot till:
%g/^/s// --option /
Kommentarer
- Vad -1 för använder ed … verkligen?
- Jag ’ inte nedröstade dig, men personen som förmodligen hade följande skäl: (1) Detta gör inte vad frågan ställer efter. Detta åberopar kommandot en gång med allt innehåll i filen på kommandoraden; snarare än en gång per rad .(2) Detta gör ingenting för att hantera tecken som är speciella för skalet (som kan finnas i filen); t.ex.
',",<,>,;, etc. (3) Detta skapar en onödig tillfällig fil. (4) Saker som detta görs vanligtvis med ”här dokument”. (5) Dinaedkommandon är klumpiga; de två första kommandona kan reduceras till%s/^/ /och%j.
<file xargs -L 1 -I{} command --option {} other args