GNU/Linux >> Znalost Linux >  >> Linux

Iterujte přes řádky místo slov ve smyčce for shell skriptu

Použití pro

for l in $() provádí dělení slov na základě IFS:

$ for l in $(printf %b 'a b\nc'); do echo "$l"; done
a
b
c
$ IFS=$'\n'; for l in $(printf %b 'a b\nc'); do echo "$l"; done
a b
c

IFS nemusí být nastaveno zpět, pokud nebude použito později.

for l in $() také provádí expanzi názvu cesty:

$ printf %b 'a\n*\n' > file.txt
$ IFS=$'\n'
$ for l in $(<file.txt); do echo "$l"; done
a
file.txt
$ set -f; for l in $(<file.txt); do echo "$l"; done; set +f
a
*

Pokud IFS=$'\n' , posuny řádků jsou odstraněny a sbaleny:

$ printf %b '\n\na\n\nb\n\n' > file.txt
$ IFS=$'\n'; for l in $(<file.txt); do echo "$l"; done
a
b

$(cat file.txt) (nebo $(<file.txt) ) také načte celý soubor do paměti.

Pomocí čtení

Bez -r se zpětná lomítka používají pro pokračování řádku a jsou odstraněna před ostatními znaky:

$ cat file.txt
\1\\2\
3
$ cat file.txt | while read l; do echo "$l"; done
1\23
$ cat file.txt | while read -r l; do echo "$l"; done
\1\\2\
3

Znaky v IFS jsou odstraněny od začátku a konce řádků, ale nejsou sbalené:

$ printf %b '1  2 \n\t3\n' | while read -r l; do echo "$l"; done
1  2
3
$ printf %b ' 1  2 \n\t3\n' | while IFS= read -r l; do echo "$l"; done
 1  2 
    3

Pokud poslední řádek nekončí novým řádkem, read mu přiřadí l, ale skončí před tělem cyklu:

$ printf 'x\ny' | while read l; do echo $l; done
x
$ printf 'x\ny' | while read l || [[ $l ]]; do echo $l; done
x
y

Pokud je smyčka while v kanálu, je také v podskořápce, takže proměnné nejsou viditelné mimo ni:

$ x=0; seq 3 | while read l; do let x+=l; done; echo $x
0
$ x=0; while read l; do let x+=l; done < <(seq 3); echo $x
6
$ x=0; x=8 | x=9; echo $x
0

for smyčka není navržena pro smyčkování přes "čáry". Místo toho přechází přes „slova“.

Krátká terminologie:„řádky“ jsou věci oddělené novými řádky. "slova" jsou věci oddělené mezerami (a mimo jiné i novými řádky). v bash žargonu se „slova“ nazývají „pole“.

Idiomatickým způsobem smyčkování řádků je použití while smyčka v kombinaci s read .

ioscan -m dsf | while read -r line
do
  printf '%s\n' "$line"
done

Všimněte si, že smyčka while je v subshell kvůli rouře. To může způsobit určitý zmatek s proměnným rozsahem. V bash to můžete obejít pomocí substituce procesů.

while read -r line
do
  printf '%s\n' "$line"
done < <(ioscan -m dsf)

viz také http://mywiki.wooledge.org/BashFAQ/024

Cyklus for rozděluje věci, které se mají opakovat, pomocí znaků v $IFS proměnné jako oddělovače. IFS je zkratka pro Internal Field Separator. Obvykle $IFS obsahuje mezeru, tabulátor a nový řádek. To znamená for smyčka bude smyčka přes "slova", nikoli přes řádky.

Pokud trváte na použití smyčky for k opakování řádků, musíte změnit hodnotu $IFS pouze na nový řádek. Ale pokud to uděláte, musíte uložit starou hodnotu $IFS a obnovit to po smyčce, protože na $IFS závisí také mnoho dalších věcí .

OLDIFS="$IFS"
IFS=$'\n' # bash specific
for line in $(ioscan -m dsf)
do
  printf '%s\n' "$line"
done
IFS="$OLDIFS"

v POSIX shellech, které nemají žádné ANSI-C citace ($'\n' ), můžete to udělat takto:

IFS='
'

to je:vložte skutečný nový řádek mezi uvozovky.

Alternativně můžete použít subshell, který obsahuje změnu na $IFS :

(
  # changes to variables in the subshell stay in the subshell
  IFS=$'\n'
  for line in $(ioscan -m dsf)
  do
    printf '%s\n' "$line"
  done
)
# $IFS is not changed outside of the subshell

Ale pozor, příkaz ve smyčce může sám o sobě záviset na nějakém rozumném nastavení pro $IFS . Poté musíte obnovit $IFS před provedením příkazu a znovu nastavte před další smyčkou nebo podobně. Nedoporučuji si zahrávat s $IFS . Příliš mnoho příkazů závisí na některých rozumných hodnotách v $IFS a jeho změna je nekonečnou noční můrou obskurního lovu brouků.

Viz také:

  • http://wiki.bash-hackers.org/syntax/ccmd/classic_for
  • http://wiki.bash-hackers.org/commands/builtin/read
  • http://mywiki.wooledge.org/IFS
  • http://mywiki.wooledge.org/SubShell
  • http://mywiki.wooledge.org/ProcessSubstitution

Linux
  1. Pokyny pro spouštění skriptů Shell pro nováčky

  2. konvence pojmenování pro shell skript a makefile

  3. Bash skript:Použití příkazu script z bash skriptu pro protokolování relace

  1. Linuxový shell skript pro zálohování databáze

  2. Spuštění pro smyčku z druhého prvku - skript Shell

  3. Transliterační skript pro linuxové prostředí

  1. Ssh – Shell skript pro přihlášení na Ssh server?

  2. Jak mohu zacyklit výstup příkazu shellu?

  3. Iterujte přes proměnnou $PATH pomocí skriptu shellu