GNU/Linux >> Znalost Linux >  >> Linux

Čtení řádků ze souboru s Bash:For vs. Zatímco?

Snažím se číst textový soubor a dělat něco s každým řádkem pomocí bash skriptu.

Takže mám seznam, který vypadá takto:

server1
server2
server3
server4

Myslel jsem, že bych to mohl opakovat pomocí smyčky while, například takto:

while read server; do
  ssh $server "uname -a"
done < /home/kenny/list_of_servers.txt

Cyklus while se zastaví po 1 spuštění, takže spustí pouze uname -a na serveru1

Nicméně se smyčkou for pomocí cat to funguje dobře:

for server in $(cat /home/kenny/list_of_servers.txt) ; do
  ssh $server "uname -a"
done

Ještě více mě zaráží, že to také funguje:

while read server; do
  echo $server
done < /home/kenny/list_of_servers.txt

Proč se můj první příklad zastaví po první iteraci?

Přijatá odpověď:

for smyčka je zde v pořádku. Ale všimněte si, že je to proto, že soubor obsahuje názvy počítačů, které neobsahují žádné mezery ani globbingové znaky. for x in $(cat file); do … nefunguje při iteraci přes řádky file obecně, protože shell nejprve rozdělí výstup z příkazu cat file kdekoli je mezera, a poté každé slovo považuje za vzor globus, takže \[?* jsou dále rozšiřovány. Můžete vytvořit for x in $(cat file) bezpečné, pokud na něm pracujete:

set -f
IFS='
'
for x in $(cat file); do …

Související čtení:Procházení souborů s mezerami v názvech?; Jak mohu číst řádek po řádku z proměnné v bash?; Proč je while IFS= read používá se tak často místo IFS=; while read.. ? Pamatujte, že při použití while read , bezpečná syntaxe pro čtení řádků je while IFS= read -r line; do … .

Nyní se podívejme na to, co se s vaším while read pokazilo pokus. Přesměrování ze souboru seznamu serverů platí pro celou smyčku. Takže když ssh běží, jeho standardní vstup pochází z tohoto souboru. Ssh klient nemůže vědět, kdy může vzdálená aplikace chtít číst ze svého standardního vstupu. Takže jakmile ssh klient zaznamená nějaký vstup, odešle tento vstup na vzdálenou stranu. Ssh server je pak připraven poskytnout tento vstup vzdálenému příkazu, pokud by to chtěl. Ve vašem případě vzdálený příkaz nikdy nečte žádný vstup, takže data skončí zahozená, ale klientská strana o tom nic neví. Váš pokus s echo fungovalo, protože echo nikdy nečte žádný vstup, nechává svůj standardní vstup na pokoji.

Existuje několik způsobů, jak se tomu vyhnout. Pomocí -n můžete ssh říct, aby nečetl ze standardního vstupu možnost.

while read server; do
  ssh -n $server "uname -a"
done < /home/kenny/list_of_servers.txt

-n volba ve skutečnosti říká ssh přesměrovat svůj vstup z /dev/null . Můžete to udělat na úrovni shellu a bude to fungovat pro jakýkoli příkaz.

while read server; do
  ssh $server "uname -a" </dev/null
done < /home/kenny/list_of_servers.txt

Lákavou metodou, jak se vyhnout vstupu ssh ze souboru, je umístit přesměrování na read příkaz:while read server </home/kenny/list_of_servers.txt; do … . To nebude fungovat, protože to způsobí, že se soubor znovu otevře při každém read se provede příkaz (takže by četl první řádek souboru znovu a znovu). Přesměrování musí být v celé smyčce while, aby byl soubor otevřen jednou po dobu trvání smyčky.

Související:BashScript funguje z Terminálu, ale ne z CronTab?

Obecným řešením je poskytnout vstup do smyčky na jiném deskriptoru souboru, než je standardní vstup. Shell má konstrukce pro přenos vstupu a výstupu z jednoho čísla deskriptoru na druhé. Zde otevřeme soubor na deskriptoru souboru 3 a přesměrujeme read standardní vstup příkazu z deskriptoru souboru 3. Klient ssh ignoruje otevřené nestandardní deskriptory, takže je vše v pořádku.

while read server <&3; do
  ssh $server "uname -a"
done 3</home/kenny/list_of_servers.txt

V bash, read příkaz má specifickou možnost číst z jiného deskriptoru souboru, takže můžete napsat read -u3 server .

Související čtení:Deskriptory souborů a skriptování shellu; Kdy byste použili další deskriptor souboru?


Linux
  1. Ekvivalentní soubor „.bashrc“ čtený všemi shelly?

  2. Nahradit řádky odpovídající vzoru řádky z jiného souboru v pořadí?

  3. Je možné v Bash začít číst soubor z libovolného offsetu počtu bajtů?

  1. Čtení Grepových vzorů ze souboru?

  2. Čtení ze souboru v sestavě

  3. Přidání časového razítka k názvu souboru s mv v BASH

  1. 10 praktických aliasů Bash pro Linux

  2. Jak naplnit soubor streamem z /dev/urandom se zadaným počtem řádků?

  3. Čtení souboru Rdata s jiným kódováním