考虑以下脚本:
#!/bin/bash
num=0
cat file | while read line; do
echo "$line"
lines[$num]="$line"
((num++))
echo "num = $num"
done
echo "end num = $num"
i=0
while [ $i -lt $num ]; do
echo "${lines[$i]}"
((i++))
done
通常,它应逐行读取文件,将结果存储在数组中,然后遍历数组并逐行打印。问题是变量$ num在第一个循环退出后以某种方式重置。我的这个脚本的输出如下(使用带有一些随机垃圾的文件):
dsfkljhhsdfsdfshdjkfgd
num = 1
fdfgdfgdfg
num = 2
dfgdfgdfgdfg
num = 3
dfgdfgdfgdfgdfg
num = 4
dfgdfgdfgdfgdfgd
num = 5
fgdfgdfgdfg
num = 6
dfgdfgdfgdfg
num = 7
dfgdfgdfgdfgdfg
num = 8
dfgdfgdfgdfg
num = 9
dfgdfgdgdgdg
num = 10
dfgdffgdgdgdg
num = 11
end num = 0
这是为什么?如何记住变量?我在SUSE Linux 10上使用bash 3.1.17。
答案 0 :(得分:15)
为什么呢?这是因为:
cat file | while read line; do
echo "$line"
lines[$num]="$line"
((num++))
echo "num = $num"
done
在一个单独的进程中运行while
语句,该进程具有自己的环境,而不是触及父环境。同样地,您会发现lines
数组也不存在。
以下简化脚本显示了这一点:
#!/bin/bash
export xyzzy=42
echo urk | while read line; do
xyzzy=999
echo $xyzzy
done
echo $xyzzy
该脚本的输出是:
999
42
因为变量设置为999
是在子流程中完成的。
最重要的是,如果您希望信息反映在当前流程(脚本)中,您需要在脚本中执行工作,或者找一些其他方法来获取信息子过程。
如果您使用输入重定向而不是启动子流程管道,它应该可以按您的需要工作。那是因为while
位然后在当前进程的上下文中完成,而不是在管道中的单独进程。例如:
#!/bin/bash
export xyzzy=42
while read line; do
xyzzy=999
echo $xyzzy
done <<EOF
hello
EOF
echo $xyzzy
将产生:
999
999
针对您的具体情况,请替换:
done <<EOF
hello
EOF
使用:
done <file
答案 1 :(得分:3)
要添加到上一个答案:并且为了避免(和UUOC),你需要这样的东西:
while ...; do
...
done < file
答案 2 :(得分:0)
只需将变量保存在同一环境中即可。在第4行,删除“cat file |”。在第9行,追加“&lt; file”。你的结束数现在将包含预期的11,而lines数组将通过你的第二个循环一次打印一个元素。