Chci napsat skript, který jako argument použije název .txt
, přečte řádek souboru podle řádku a předá každý řádek příkazu. Například spustí příkaz command --option "LINE 1"
, poté command --option "LINE 2"
atd. Výstup příkazu je zapsán do jiného souboru. Jak to mám udělat? Nevím, kde začít.
Odpovědět
Použijte while read
smyčku:
: > another_file ## Truncate file. while IFS= read -r LINE; do command --option "$LINE" >> another_file done < file
Další možností je přesměrovat výstup pomocí bloku:
while IFS= read -r LINE; do command --option "$LINE" done < file > another_file
Poslední je otevření souboru:
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
Pokud jeden z příkazů přečte vstup, bylo by dobré nápad použít pro vstup další fd, takže příkazy to nebudou jíst (zde za předpokladu ksh
, zsh
nebo bash
pro -u 3
použijte <&3
místo toho přenosně):
while IFS= read -ru 3 LINE; do ... done 3< file
Fin spojenec pro přijetí argumentů, můžete udělat:
#!/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"
Který z nich může běžet jako:
bash script.sh file another_file
Extra nápad. V bash
použijte readarray
:
readarray -t LINES < "$FILE" for LINE in "${LINES[@]}"; do ... done
Poznámka: IFS=
lze vynechat, pokud vám nevadí, že řádkové hodnoty budou oříznuty na začátku a na konci mezer.
Odpovědět
Další možností je xargs
.
S GNU xargs
:
xargs -a file -I{} -d"\n" command --option {} other args
{}
je zástupný znak pro řádek textu.
Další xargs
obecně nemají -a
, -d
, ale některé mají -0
pro vstup oddělený NUL. S nimi můžete:
< file tr "\n" "\0" | xargs -0 -I{} command --option {} other args
V systémech vyhovujících Unixu (-I
je v POSIXu volitelný a pouze vyžadováno pro systémy vyhovující systému UNIX), je třeba předem zpracovat vstup pro citaci řádků ve formátu očekávaném xargs
:
< file sed "s/"/"\\""/g;s/.*/"&"/" | xargs -E "" -I{} command --option {} other args
Mějte však na paměti, že některé implementace xargs
mají velmi nízkou hranici maximální velikosti argumentu (například 255 v systému Solaris, minimum povolené specifikací Unixu.
Komentáře
Odpověď
Přesné dodržování na otázku:
#!/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
Komentáře
- fungovaly jako kouzlo 🙂
- +1 se to líbilo, díky
odpověď
nejlepší odpověď und je:
for i in `cat`; do "$cmd" "$i"; done < $file
EDIT:
… o čtyři roky později …
po několika hlasováních dolů a dalších zkušenostech bych teď doporučil následující:
xargs -l COMMAND < file
Komentáře
- Tím se příkaz vyvolá jednou pro každé word v souboru. Měli byste také vždy citovat odkazy na proměnné prostředí (jako v
do "$cmd" "$i";
), pokud pro to nemáte důvod; pokud soubor obsahoval*
jako slovo samo o sobě, váš kód by spustil$cmd *
, což by samozřejmě spustilo příkaz s seznam souborů v aktuálním adresáři. - @ G-Man, kromě
zsh
,`cat`
by již rozšířil*
(nekótovaný$i
by mohl ještě rozšířit nějaký zástupný znak (druhé kolo), pokud by rozšíření`cat`
zavádí některé). V každém případě je tento přístup skutečně špatný. - +1. To bude fungovat dobře, pokud každý řádek obsahuje pouze vstup potřebný pro použitý příkaz bez mezer.
- +1, oblíbené řešení xargs
- to funguje! (pozdější úprava
xargs -l COMMAND < file
). Děkujeme!
Odpověď
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
VÝSTUP
--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
Odpověď
ed file.txt %g/^/s// / 2,$g/^/-,.j 1s/^/command/ wq chmod 755 file.txt ./file.txt
Vezměte všechny řádky souboru a předat je jako argumenty jedinému příkazu, tj.
command line1 line2 line3 ....
Pokud potřebujete --option
příznak před každým řádkem změňte druhý příkaz na:
%g/^/s// --option /
Komentáře
- Co -1 pro používám ed … opravdu?
- Nechtěl jsem tě ' přehlasovat, ale ten, kdo to udělal, měl pravděpodobně tyto důvody: (1) To nedělá na co se otázka ptá. Toto vyvolá příkaz jednou se všemi obsahy souboru na příkazovém řádku; spíše než jednou na řádek .(2) Nedělá to nic pro zpracování znaků, které jsou speciální pro shell (který může být v souboru); např.
'
,"
,<
,>
,;
atd. (3) Tím se vytvoří nepotřebný dočasný soubor. (4) Věci jako toto se obvykle dějí s „zde dokumenty“. (5) Vašeed
příkazy jsou neohrabané; první dva příkazy lze snížit na%s/^/ /
a%j
.
<file xargs -L 1 -I{} command --option {} other args