为什么FILE_FOUND在这个bugger的末尾为0:
FILE_FOUND=0
touch /tmp/$$.txt
ls -1 /tmp/$$.* 2>/dev/null | while read item; do
FILE_FOUND=1
echo "FILE_FOUND = $FILE_FOUND"
done
echo "FILE_FOUND = $FILE_FOUND"
rm -f /tmp/$$.txt 2>/dev/null
?? !!
在Unix上,FILE_FOUND保持为1(应该如此),但在Linux(RedHat,Cygwin,..)上它会跳回到0 !!
它是Linux shell功能,而不是bug吗? :)
请帮忙。
答案 0 :(得分:5)
由于您正在流入while而导致的常见问题,因此在子shell中运行,而子shell无法将环境变量传递回其父级。我猜这个“unix”在这方面有所不同,因为你在那里运行一个不同的shell(ksh?)
可能不需要连接到while循环。你能用这个成语吗?
for item in /tmp/$$.*; do
....
done
如果你必须使用子shell,那么你必须做一些外部的事情,比如:
touch /tmp/file_found
答案 1 :(得分:3)
这是“bash”shell的“功能”。 “bash”手册条目清楚地说明了这一点:
管道中的每个命令都作为一个单独的进程执行(即在子shell中)。
使用Korn shell(“ksh”)执行的相同构造在同一进程中运行“while”(不在子shell中),因此给出了预期的答案。所以我检查了规格。
POSIX shell specification对此并不十分清楚,但它没有说明改变“shell执行环境”,所以我认为UNIX / Korn shell实现是兼容的并且Bourne Again shell实现是不。但是,“bash”并不声称符合POSIX!
答案 2 :(得分:2)
已经提到过了,但是由于你正在流行,所以整个while循环都在子shell中运行。我不确定你在'Unix'上使用哪个shell,我认为这意味着Solaris,但bash应该表现得一致,无论平台如何。
要解决这个问题,你可以做很多事情,最常见的是以某种方式检查while循环的结果,就像这样
result=`mycommand 2>/dev/null | while read item; do echo "FILE_FOUND"; done`
并在$result
中查找数据。另一种常见的方法是让while循环产生有效的变量赋值,并直接评估它。
eval `mycommand | while read item; do echo "FILE_FOUND=1"; done`
将由您的'当前'shell评估以分配给定的变量。
我假设你不想只是迭代文件,在这种情况下你应该做
for item in /tmp/$$.*; do
# whatever you want to do
done
答案 3 :(得分:2)
正如其他人所提到的,它是你使用管道符号创建的额外shell。试试这个:
while read item; do
FILE_FOUND=1
echo "FILE_FOUND = $FILE_FOUND"
done < <(ls -1 /tmp/$$.* 2>/dev/null)
在这个版本中,while
循环在你的脚本的shell中,而ls
是一个新的shell(与你的脚本正在做的相反)。
答案 4 :(得分:0)
另一种方式,将结果带回来,
FILE_FOUND=0
result=$(echo "something" | while read item; do
FILE_FOUND=1
echo "$FILE_FOUND"
done )
echo "FILE_FOUND outside while = $result"
答案 5 :(得分:-2)
嗯... ls -1
而不是l
在你的剧本上?