Ik “ben op zoek naar een script dat een .txt
bestandsnaam als argument moet nemen, leest de bestandsregel by line, en geeft elke regel door aan een commando. Het voert bijvoorbeeld command --option "LINE 1"
uit, vervolgens command --option "LINE 2"
, enz. De uitvoer van het commando wordt naar een ander bestand geschreven. Hoe pak ik dat aan? Ik weet niet waar ik moet beginnen.
Antwoord
Gebruik while read
loop:
: > another_file ## Truncate file. while IFS= read -r LINE; do command --option "$LINE" >> another_file done < file
Een andere is om de uitvoer per blok om te leiden:
while IFS= read -r LINE; do command --option "$LINE" done < file > another_file
De laatste is om het bestand te openen:
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
Als een van de commandos invoer leest, zou het een goede idee om een andere fd te gebruiken voor invoer, zodat de commandos het niet opeten (in de veronderstelling dat ksh
, zsh
of bash
voor -u 3
, gebruik <&3
in plaats daarvan draagbaar):
while IFS= read -ru 3 LINE; do ... done 3< file
Fin bondgenoot om argumenten te accepteren, kunt u het volgende doen:
#!/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"
Welke kan worden uitgevoerd als:
bash script.sh file another_file
Extra idee. Gebruik met bash
readarray
:
readarray -t LINES < "$FILE" for LINE in "${LINES[@]}"; do ... done
Opmerking: IFS=
kan worden weggelaten als u het niet erg vindt dat regelwaarden worden bijgesneden van voorloop- en volgspaties.
Antwoord
Een andere optie is xargs
.
Met GNU xargs
:
xargs -a file -I{} -d"\n" command --option {} other args
{}
is de plaatshouder voor de regel tekst.
Overig xargs
hebben over het algemeen geen -a
, -d
, maar sommige hebben -0
voor NUL-gescheiden invoer. Hiermee kunt u het volgende doen:
< file tr "\n" "\0" | xargs -0 -I{} command --option {} other args
Op Unix-conforme systemen (-I
is optioneel in POSIX en alleen vereist voor UNIX-conforme systemen), “zou je de invoer moeten voorverwerken tot quote de regels in het formaat dat wordt verwacht door xargs
:
< file sed "s/"/"\\""/g;s/.*/"&"/" | xargs -E "" -I{} command --option {} other args
Merk echter op dat sommige xargs
implementaties een zeer lage limiet hebben voor de maximale grootte van het argument (255 op Solaris bijvoorbeeld, het minimum toegestaan door de Unix-specificatie).
Reacties
Antwoord
Precies houden op de vraag:
#!/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
Reacties
- werkte prima 🙂
- +1 vond dit geweldig, bedankt
Antwoord
Het beste antwoord dat ik voor und is:
for i in `cat`; do "$cmd" "$i"; done < $file
EDIT:
… vier jaar later …
na verschillende stemmen en wat meer ervaring zou ik “nu het volgende aanbevelen:
xargs -l COMMAND < file
Reacties
- Dit zal het commando één keer aanroepen voor elk woord in het bestand. Je moet ook altijd verwijzingen naar shell-variabelen citeren (zoals in
do "$cmd" "$i";
), tenzij je een reden hebt om dat niet te doen; als het bestand een*
als een woord op zich zou bevatten, zou uw code$cmd *
uitvoeren, waarmee de opdracht natuurlijk zou worden uitgevoerd met een lijst van de bestanden in de huidige directory. - @ G-Man, behalve in
zsh
, de`cat`
zou de*
al uitbreiden (de niet-geciteerde$i
zou nog steeds een jokerteken kunnen uitbreiden (een tweede ronde) als de uitbreiding van`cat`
introduceert enkele). In elk geval is die benadering inderdaad verkeerd. - +1. Dit werkt prima, als elke regel alleen de invoer bevat die nodig is voor het commando dat zonder spaties wordt gebruikt.
- +1, vond xargs-oplossing leuk
- Dit werkt! (de latere bewerking
xargs -l COMMAND < file
). Bedankt!
Antwoord
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
Antwoord
ed file.txt %g/^/s// / 2,$g/^/-,.j 1s/^/command/ wq chmod 755 file.txt ./file.txt
Neem alle regels van een bestand en geef ze als argumenten door aan een enkel commando, dwz
command line1 line2 line3 ....
Als je de --option
vlag om aan elke regel vooraf te gaan, verander het tweede commando in:
%g/^/s// --option /
Reacties
- Wat -1 voor gebruik ik ed … echt?
- Ik heb je ‘ niet naar beneden gestemd, maar de persoon die dat wel deed, had waarschijnlijk de volgende redenen: (1) Dit doet niet wat de vraag vraagt. Dit roept het commando eenmaal op met alle inhoud van het bestand op de commandoregel; in plaats van eenmaal per regel .(2) Dit doet niets om tekens te behandelen die speciaal zijn voor de shell (die mogelijk in het bestand staan); bijv.
'
,"
,<
,>
,;
, etc. (3) Dit creëert een onnodig tijdelijk bestand. (4) Dit soort dingen wordt over het algemeen gedaan met “hier documenten”. (5) Uwed
opdrachten zijn onhandig; de eerste twee commandos kunnen worden teruggebracht tot%s/^/ /
en%j
.
<file xargs -L 1 -I{} command --option {} other args