我有一个变量,我试图设置这样的东西:
#!/bin/sh
found=0
id=1
echo "Hello" |
while [ $id != 5 ]
do
id=`expr $id + 1`
echo $id
found=1
done
echo "found = $found" // I expect this to be 1
为什么以及如何设置此值? 我被迫使用这样(管道),因为生产环境中的实际代码是:
found=0
id=1
my_mount_name="/opt/insiteone/fuse-mount"
echo "select file_system_id, mount_name from SystemTable" | mysql ifm -uroot -pinsite3 |
while read file_system_id mount_name
do
if [ "$id" == "$file_system_id" -a "$my_mount_name" == "$mount_name" ]; then
echo "Match found for file system ID and mount name"
found=1
fi
done
echo "found = $found" // I expect this to be 1, when a match, but does not
答案 0 :(得分:4)
管道在子壳中运行。你可以做一些事情来使它工作,最简单的是:
found=0
id=1
my_mount_name="/opt/insiteone/fuse-mount"
echo "select file_system_id, mount_name from SystemTable" |
mysql ifm -uroot -pinsite3 | {
while read file_system_id mount_name
do
if [ "$id" == "$file_system_id" -a "$my_mount_name" == "$mount_name" ]; then
echo "Match found for file system ID and mount name"
found=1
fi
done
echo "found = $found"; }
# Note the enclosing {}. Inside the black, the variable $found is set.
# After this comment, it will be zero.
这种技术可能要求封闭块相当大,因此您可能需要重构脚本的其余部分以使其可用。另一种选择是使用fifo或将echo / mysql管道放入进程替换中。 (后者不是可移植的,但在bash中工作可能就足够了。)但是,在这种特殊情况下,最好做一些类似的事情:
found=0
id=1
my_mount_name="/opt/insiteone/fuse-mount"
echo "select file_system_id, mount_name from SystemTable" |
mysql ifm -uroot -pinsite3 | {
while read file_system_id mount_name
do
if [ "$id" == "$file_system_id" -a "$my_mount_name" == "$mount_name" ]; then
echo "Match found for file system ID and mount name"
exit 0 # Exit the subshell succesfully
fi
done
exit 1; } && found=1
答案 1 :(得分:3)
您可以将变量传递给子shell的environemnt:
foo=1
bar=2
echo "sds" | foo="$foo" bar="$bar" while ...
答案 2 :(得分:2)
正如@fedorqui评论的那样,bash将管道组件放在不同的子shell中,因此当子shell退出时,对变量的更改会消失。
有两种策略可以解决这个问题:
仅在同一子shell中使用已更改的变量
echo "Hello" |
{
while [ $id != 5 ]
do
((id++))
echo $id
found=1
done
echo "found = $found" // I expect this to be 1
}
如果你有很多依赖这些变量的代码
用流程替换替换管道。这意味着while循环不在子shell中执行,它在当前shell中运行:
while [ $id != 5 ]
do
((id++))
echo $id
found=1
done < <(echo "Hello")
echo "found = $found" // I expect this to be 1
这可能会导致可读性差,但您可以根据需要在<(...)
内放置尽可能多的换行符。
您的生产代码使用流程替换(和bash / ksh条件语法)重写:
found=0
id=1
my_mount_name="/opt/insiteone/fuse-mount"
while read file_system_id mount_name; do
if [[ $id == $file_system_id ]] && [[ $my_mount_name == $mount_name ]]; then
echo "Match found for file system ID and mount name"
found=1
fi
done < <(
echo "select file_system_id, mount_name from SystemTable" |
mysql ifm -uroot -pinsite3
)
echo "found = $found"