为什么此SH脚本生成以下输出

LDK*_*LDK 2 shell

码:

while read line;
do
  tr 3 4
done<<EOF
1
2
3
4
EOF
Run Code Online (Sandbox Code Playgroud)

生产:

2
4
4

1去哪儿了?

Ste*_*ini 7

$ while read line
> do
>     tr 3 4
> done<<EOF
> 1
> 2
> 3
> 4
> EOF
2
4
4
Run Code Online (Sandbox Code Playgroud)

这里发生的是read line获得第一行的1.输入的其余部分传递给tr,用4替换3,所以2 3 4变为2 4 4

1进入变量线.例

$ while read foo; do echo "This is $foo"; done <<EOF
> madness
> SPARTAAAAAAAAAAAA
> EOF
This is madness
This is SPARTAAAAAAAAAAAA
Run Code Online (Sandbox Code Playgroud)

你看到的奇怪行为是因为read是内置的,并且有些特殊.例如,当你执行管道时,假设你写了

echo "foo bar" | read i
Run Code Online (Sandbox Code Playgroud)

你会期待$ i中的某些东西,对吗?试试吧,它会是空的.为什么?当您进行管道连接时,管道的每个命令都在子shell中运行.这对所有事情都是如此,而且永远如此.

read有点奇怪,因为它不是命令,它是shell的内置函数,它必须导出一个变量才能看到它.如果您使用管道,就像上面的示例一样,它将i在子进程(子shell)中导出,您将永远不会看到它,因为您正在使用的shell环境是父级,并且子shell无法设置其环境家长.

在你的情况下,会发生的事情是read,与while内置函数一起,在你的shell中运行.read尽职尽责地完成从stdin获取第一件事并将其设置为同一shell的变量的工作.这将从stdin中删除1,因为这是read builtin所做的.stdin现在留下剩余的东西,它被传递给tr,因为在那时,stdin被第一个命令拦截.试试这个

$ while true; do rev; echo "x"; done <<EOF
> hello
> EOF
olleh
Run Code Online (Sandbox Code Playgroud)

你会留下一堆x.rev已经完成(检查其在第一行中的输出),并且stdin已关闭(您使用EOF执行此操作).while循环将永远持续(并且你将得到一个x级联)但你不能再提供任何东西到rev,因为你不再输入stdin了.