我有一个循环检查是否跳到下一次迭代的某些标准(A)。我意识到,如果我调用一个skip
调用 的函数 ( ) continue
,就好像它是在子进程中调用的,因为它看不到循环 (B)。此外,建议的依赖于eval
字符串的解决方法也不起作用 (C)。
# /usr/bin/bash env
skip()
{
echo "skipping : $1"
continue
}
skip_str="echo \"skipping : $var\"; continue"
while read -r var;
do
if [[ $var =~ ^bar$ ]];
then
# A
# echo "skipping : $var"
# continue
# B
# skip "$var" # continue: only meaningful in a `for', `while', or `until' loop
# C
eval "$skip_str"
fi
echo "processed: $var"
done < <(cat << EOF
foo
bar
qux
EOF
)
方法C:
$ source ./job-10.sh
processed: foo
skipping :
processed: qux
另请参阅:
PS1:有人可以提醒我为什么< <
而不是<
之后需要done
吗?
PS2:没有找到while
因此的标签for
答案1
该函数确实在同一个进程中运行,只是在语法上与循环不同。在几乎任何其他编程语言中,您也不能在函数内部使用break
或来影响其外部的循环。continue
但实际上,在外壳中,未指定:
continue [n]
如果n指定后,继续实用程序应返回到顶部nth 包含 for、while 或 Until 循环。如果n未指定,继续的行为就像n被指定为 1。[...][...]如果没有封闭循环,则行为未指定。
你得到什么取决于外壳:
Bash 给出错误并忽略continue
:
$ bash -c 'f() { continue; }; for x in a b c; do f; echo $x; done; echo done'
environment: line 0: continue: only meaningful in a ‘for’, ‘while’, or ‘until’ loop
a
environment: line 0: continue: only meaningful in a ‘for’, ‘while’, or ‘until’ loop
b
environment: line 0: continue: only meaningful in a ‘for’, ‘while’, or ‘until’ loop
c
done
Ksh 默默地忽略它:
$ ksh -c 'f() { continue; }; for x in a b c; do f; echo $x; done; echo done'
a
b
c
done
虽然 Dash、Yash 和 Zsh 实际上确实应用了它:
$ dash -c 'f() { continue; }; for x in a b c; do f; echo $x; done; echo done'
done
我确实预计类似的考虑因素eval
也可能适用于使用,但情况似乎并非如此。至少我看不出外壳之间有任何区别。
总而言之,不要这样做。只要写出来:
while read -r var;
do
if [[ $var =~ ^bar$ ]];
then
echo "skipping '$var'"
continue
fi
echo "processed: $var"
done
答案2
问题是当你的函数被执行时,它不再在循环内。它不在子外壳中,不,但它也不在任何循环内。就该函数而言,它是一段独立的代码,并且不知道它是从哪里调用的。
然后,当您运行时,eval "$skip_str"
没有值,因为您在未定义的时间$var
设置了。这实际上应该按照您的预期工作,它只是无缘无故地非常复杂和危险(如果您不 100% 控制输入):skip_string
$var
#! /usr/bin/env bash
while read -r var;
do
skip_str="echo \"skipping : $var\"; continue"
if [[ $var =~ ^bar$ ]];
then
eval "$skip_str"
fi
echo "processed: $var"
done < <(cat << EOF
foo
bar
qux
EOF
)
那……确实不太漂亮。就我个人而言,我只会使用一个函数来进行测试,然后对测试结果进行操作。像这样:
#! /usr/bin/env bash
doTest(){
if [[ $1 =~ ^bar$ ]];
then
return 1
else
return 0
fi
}
while read -r var;
do
if doTest "$var"; then
echo "processed: $var"
else
echo "skipped: $var"
continue
fi
## Rest of your code here
done < <(cat << EOF
foo
bar
qux
EOF
)
如果你解释一下你的目标是什么,我可能会给你更好的东西。
最后,你不需要< <
after done
,你需要< <()
。是<
正常的输入重定向,<()
称为流程替代and 是一个技巧,可以让您将命令的输出视为文件名。
如果您使用该函数只是为了避免重复诸如 之类的额外内容echo "skipping $1"
,则可以简单地将更多逻辑移至该函数中,以便在那里有一个循环。像这样的东西:关联