Pet*_*r.O 14 shell text-processing environment-variables
我可能有一些绝对错误的地方,但对我来说看起来很有说服力,将 IFS 设置为pre-do/done 列表中的命令之一绝对没有效果。
外部 IFS(while构造外部)在下面脚本中显示的所有示例中都占优势。
这里发生了什么?我对 IFS 在这种情况下的作用有什么误解吗?我希望数组拆分结果如“预期”列中所示。
#!/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=$' \t\n'; xifs "$IFS"; echo "$data" | while read; do echo -ne '\t 1'; show "$REPLY"; done
IFS=$' \t\n'; xifs "$IFS"; echo "$data" | while IFS= read; do echo -ne '\t 2'; show "$REPLY"; done
IFS=$' \t\n'; 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-----"
Run Code Online (Sandbox Code Playgroud)
输出:
----- -- -- -------- 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=" "
----- -- -- -------- ----- --------- -------
Run Code Online (Sandbox Code Playgroud)
Sté*_*nez 19
(对不起,解释太长了)
是的,IFS变量 inwhile IFS=" " read; do …对代码的其余部分没有影响。
让我们首先明确 shell 命令行具有两种不同类型的变量:
fork()and 上exec(),因此子进程继承它们。当您使用以下命令调用命令时:
A=foo B=bar command
Run Code Online (Sandbox Code Playgroud)
该命令在 (environment) 变量A设置为foo并且B设置为的环境中执行bar。但是,使用此命令行,当前shell变量A和B被留下不变。
这不同于:
A=foo; B=bar; command
Run Code Online (Sandbox Code Playgroud)
在这里,定义了shell 变量A和B并且命令在没有环境变量的情况下运行A并B定义。值A和B来自不可访问command。
但是,如果某些 shell 变量被export-ed,则相应的环境变量会与它们各自的 shell 变量同步。例子:
export A
export B
A=foo; B=bar; command
Run Code Online (Sandbox Code Playgroud)
使用此代码,shell变量和 shell环境变量都设置为foo和bar。由于环境变量由子进程继承,command将能够访问它们的值。
要跳回您的原始问题,请在:
IFS='a' read
Run Code Online (Sandbox Code Playgroud)
只read受影响。而事实上,在这种情况下,read并不关心IFS变量的值。它IFS仅在您要求分割行(并存储在多个变量中)时使用,例如:
echo "a : b : c" | IFS=":" read i j k; \
printf "i is '%s', j is '%s', k is '%s'" "$i" "$j" "$k"
Run Code Online (Sandbox Code Playgroud)
IFSread除非使用参数调用,否则不使用。(编辑:这不完全正确:IFS在输入行的开头/结尾总是忽略空格字符,即空格和制表符。)
简而言之,您必须一次读取多个变量,以便IFS=<something> read ...构造在您的示例1 中产生可见效果。
您错过read了示例中的范围。有没有在你的测试用例环内IFS的修改。请允许我准确指出,第二个 IFS 在你的每一行中都有什么影响:
IFS=$' \t\n'; xifs "$IFS"; echo "$data" | while IFS=b read; do echo ...
^ ^
| |
from here --' `- to here :)
Run Code Online (Sandbox Code Playgroud)
就像在 shell 中执行的任何程序一样。您在命令行(重新)定义的变量会影响程序执行。而仅是(因为你不出口)。因此,要IFS在这样的行中使用 redefined ,您必须要求read将值分配给多个变量。看看这些例子:
$ data="a b c"
$ echo "$data" | while read A B C; do echo \|$A\|$B\|\|$C\|; done
|a|b||c|
$ echo "$data" | while IFS= read A B C; do echo \|$A\|$B\|\|$C\|; done
|a b c||||
$ echo "$data" | while IFS='a' read A B C; do echo \|$A\|$B\|\|$C\|; done
|| b c|||
$ echo "$data" | while IFS='ab' read A B C; do echo \|$A\|$B\|\|$C\|; done
|| || c|
Run Code Online (Sandbox Code Playgroud)
1正如我刚刚从 Gilles学到的那样,IFS=''当只读取一个字段时,设置(空白)实际上可能有一个好处:它避免了行首的空格被截断。