Možná mám něco úplně špatně, ale zdá se mi přesvědčivé, že nastavení IFS jako jednoho z příkazů v seznamu pre-do/done nemá absolutně žádný vliv.
Vnější IFS (mimo while
konstrukt) převládá ve všech příkladech zobrazených ve skriptu níže..
Co se tam děje? Mám špatnou představu o tom, co IFS v této situaci dělá? Očekával jsem, že výsledky rozdělení pole budou takové, jaké jsou uvedeny ve sloupci „očekávané“.
#!/bin/bash
xifs() { echo -n "$(echo -n "$IFS" | xxd -p)"; } # allow for null $IFS
show() { x=($1)
echo -ne " (${#x[@]})t |"
for ((j=0;j<${#x[@]};j++)); do
echo -n "${x[j]}|"
done
echo -ne "t"
xifs "$IFS"; echo
}
data="a b c"
echo -e "----- -- -- t --------tactual"
echo -e "outside t IFS tinside"
echo -e "loop t Field tloop"
echo -e "IFS NR NF t Split tIFS (actual)"
echo -e "----- -- -- t --------t-----"
IFS=$' tn'; xifs "$IFS"; echo "$data" | while read; do echo -ne 't 1'; show "$REPLY"; done
IFS=$' tn'; xifs "$IFS"; echo "$data" | while IFS= read; do echo -ne 't 2'; show "$REPLY"; done
IFS=$' tn'; xifs "$IFS"; echo "$data" | while IFS=b read; do echo -ne 't 3'; show "$REPLY"; done
IFS=" "; xifs "$IFS"; echo "$data" | while read; do echo -ne 't 4'; show "$REPLY"; done
IFS=" "; xifs "$IFS"; echo "$data" | while IFS= read; do echo -ne 't 5'; show "$REPLY"; done
IFS=" "; xifs "$IFS"; echo "$data" | while IFS=b read; do echo -ne 't 6'; show "$REPLY"; done
IFS=; xifs "$IFS"; echo "$data" | while read; do echo -ne 't 7'; show "$REPLY"; done
IFS=; xifs "$IFS"; echo "$data" | while IFS=" " read; do echo -ne 't 8'; show "$REPLY"; done
IFS=; xifs "$IFS"; echo "$data" | while IFS=b read; do echo -ne 't 9'; show "$REPLY"; done
IFS=b; xifs "$IFS"; echo "$data" | while IFS= read; do echo -ne 't10'; show "$REPLY"; done
IFS=b; xifs "$IFS"; echo "$data" | while IFS=" " read; do echo -ne 't11'; show "$REPLY"; done
echo -e "----- -- -- t --------t-----"
Výstup:
----- -- -- -------- actual
outside IFS inside assigned
loop Field loop # inner
IFS NR NF Split IFS # expected IFS
----- -- -- -------- ----- # --------- --------
20090a 1 (3) |a|b|c| 20090a #
20090a 2 (3) |a|b|c| 20090a # |a b c| IFS=
20090a 3 (3) |a|b|c| 20090a # |a | c| IFS=b
20 4 (3) |a|b|c| 20 #
20 5 (3) |a|b|c| 20 # |a b c IFS=
20 6 (3) |a|b|c| 20 # |a | c| IFS=b
7 (1) |a b c| #
8 (1) |a b c| # |a|b|c| IFS=" "
9 (1) |a b c| # |a | c| IFS=b
62 10 (2) |a | c| 62 # |a b c| IFS=
62 11 (2) |a | c| 62 # |a|b|c| IFS=" "
----- -- -- -------- ----- --------- -------
Přijatá odpověď:
(Omlouvám se, dlouhé vysvětlení)
Ano, IFS
proměnná v while IFS=" " read; do …
nemá žádný vliv na zbytek kódu.
Nejprve upřesněme, že příkazový řádek shellu obsahuje dva různé druhy proměnných:
- proměnné shellu (které existují pouze v rámci shellu a jsou lokální pro shell)
- proměnné prostředí, které existují pro každý proces. Ty jsou obvykle zachovány na
fork()
aexec()
, takže je podřízené procesy zdědí.
Když zavoláte příkaz pomocí:
A=foo B=bar command
příkaz se provádí v prostředí, kde (prostředí) proměnná A
je nastaveno na foo
a B
je nastavena na bar
. Ale s tímto příkazovým řádkem jsou aktuální proměnné shellu A
a B
jsou ponechány beze změny .
To se liší od:
A=foo; B=bar; command
Zde shellové proměnné A
a B
jsou definovány a příkaz je spuštěn bez proměnných prostředí A
a B
definována. Hodnoty A
a B
jsou nepřístupné z command
.
Pokud jsou však některé proměnné shellu export
-ed, odpovídající proměnné prostředí jsou synchronizovány s jejich příslušnými proměnnými prostředí. Příklad:
export A
export B
A=foo; B=bar; command
S tímto kódem se oba skryjí proměnné a prostředí shellu proměnné jsou nastaveny na foo
a bar
. Protože proměnné prostředí dědí dílčí procesy, command
budou mít přístup k jejich hodnotám.
Chcete-li se vrátit k původní otázce, v:
IFS='a' read
pouze read
je ovlivněna. A ve skutečnosti v tomto případě read
nezajímá se o hodnotu IFS
variabilní. Používá IFS
pouze když požádáte o rozdělení řádku (a uložení do několika proměnných), jako v:
echo "a : b : c" | IFS=":" read i j k;
printf "i is '%s', j is '%s', k is '%s'" "$i" "$j" "$k"
IFS
read
nepoužívá pokud není volána s argumenty. (Upravit: Není to tak úplně pravda:mezery, tj. mezera a tabulátor, jsou v IFS
jsou vždy ignorovány na začátku/konci vstupního řádku. )