在下面的程序中,如果我在第一个 if
语句中将变量 $foo
设置为值1,那么它的作用就是在if语句之后记住它的值 . 但是,当我在 if
语句中的 if
内将相同的变量设置为值2时,在 while
循环之后它被遗忘了 . 它's behaving like I' m在 while
循环中使用变量 $foo
的某种副本,我只修改该特定副本 . 这是一个完整的测试程序:
#!/bin/bash
set -e
set -u
foo=0
bar="hello"
if [[ "$bar" == "hello" ]]
then
foo=1
echo "Setting \$foo to 1: $foo"
fi
echo "Variable \$foo after if statement: $foo"
lines="first line\nsecond line\nthird line"
echo -e $lines | while read line
do
if [[ "$line" == "second line" ]]
then
foo=2
echo "Variable \$foo updated to $foo inside if inside while loop"
fi
echo "Value of \$foo in while loop body: $foo"
done
echo "Variable \$foo after while loop: $foo"
# Output:
# $ ./testbash.sh
# Setting $foo to 1: 1
# Variable $foo after if statement: 1
# Value of $foo in while loop body: 1
# Variable $foo updated to 2 inside if inside while loop
# Value of $foo in while loop body: 2
# Value of $foo in while loop body: 2
# Variable $foo after while loop: 1
# bash --version
# GNU bash, version 4.1.10(4)-release (i686-pc-cygwin)
6 回答
while
循环在子shell中执行 . 因此,一旦子shell退出,您对该变量所做的任何更改都将无法使用 .相反,您可以使用here string重新编写while循环以进入主shell进程;只有
echo -e $lines
将在子shell中运行:UPDATED#2
Blue Moons的答案是解释 .
替代方案:
消除
echo
在here-is-the-document中添加echo
在后台运行
echo
:显式重定向到文件句柄(注意
< <
中的空格!):或者只是重定向到
stdin
:一个用于
chepner
(消除echo
):变量
$lines
可以转换为数组而无需启动新的子shell . 字符\
和n
必须转换为某个字符(例如,一个真正的新行字符),并使用IFS(内部字段分隔符)变量将字符串拆分为数组元素 . 这可以这样做:结果是
您是第742342位用户问这个bash FAQ.该答案还描述了管道创建的子壳中设置的变量的一般情况:
嗯......我几乎发誓,这适用于原始的Bourne shell,但是现在无法访问正在运行的副本来检查 .
但是,这个问题有一个非常简单的解决方法 .
从以下位置更改脚本的第一行:
至
瞧瞧!假设您安装了Korn shell,那么管道末端的读取工作正常 .
这是一个有趣的问题,触及一个非常基本的概念Bourne shell和subshell . 在这里,我通过某种过滤提供了与以前的解决方案不同的解决方案 . 我将举一个可能在现实生活中有用的例子 . 这是用于检查下载的文件是否符合已知校验和的片段 . 校验和文件如下所示(仅显示3行):
shell脚本:
parent和subshell通过echo命令进行通信 . 您可以为父shell选择一些易于解析的文本 . 这种方法不会破坏你的正常思维方式,只是你必须做一些后期处理 . 您可以使用grep,sed,awk等来执行此操作 .
怎么样一个非常简单的方法