带参数和 eval 的条件构造
Conditional construct with parameter and eval
考虑以下代码。如果我删除 eval
而只是写 if ""
它不起作用。是否可以去掉 eval
?
assert () {
if eval "" #Is it possible to get rid of the eval?
then
echo "Assertion OK: \"\""
else
echo "Assertion FAILED: \"\""
fi
}
assert " [[ /tmp/a = /tmp/* ]]"
可以在不使用 eval
的情况下创建一个有用的 assert
函数:
function assert
{
local IFS # Protect "$*" against an unusual IFS value in the caller
if "$@"; then
printf 'Assertion OK: "%s"\n' "$*"
else
printf 'Assertion FAILED: "%s"\n' "$*"
fi
}
示例使用:
assert [ -f /etc/passwd ] # OK
assert [ ! -f /etc/group ] # FAILED
var1='a b'
var2='a b'
var3='-c'
assert [ "$var1" = "$var2" ] # OK
assert [ "$var2" = "$var3" ] # FAILED
assert grep -q '^guest:' /etc/passwd # Maybe OK, maybe FAILED
当命令(</code>)是用户自定义函数(例如<code>dostuff
),Bash内置命令(例如[
或 test
),或外部命令(例如 grep
)。
由于 Bash 处理代码行的方式,如果命令是 Bash reserved word (aka "keyword"). See the accepted answer to What's the difference between shell builtin and shell keyword? 以获得极好的相关信息,该函数将不起作用。特别是,它涵盖了 [ ... ]
和 [[ ... ]]
之间的重要区别。标准 Bash 文档在这方面很差。
[[
是保留字,所以这个不行:
assert [[ /tmp/a = '/tmp/*' ]] # Error: '[[' command not found
由于Bash对[[ ... ]]
里面的代码做了特殊处理,我觉得不可能修改assert
函数让assert [[ ...
在里面工作所有情况。在不使用 eval
的情况下解决该问题的一种方法是在功能重叠的情况下使用 [
而不是 [[
(文件访问测试、简单的字符串比较,...)并使用特殊的 assert_*
函数实现 [[
的特殊功能。例如,此函数测试 (glob) 模式匹配:
function assert_match
{
local -r str=
local -r pat=
# shellcheck disable=SC2053 # (Bad warning about not quoting $pat)
if [[ $str == $pat ]]; then
printf 'assert_match OK: "%s" matches "%s"\n' "$str" "$pat"
else
printf 'assert_match FAILED: "%s" does not match "%s"\n' "$str" "$pat"
fi
}
示例使用:
assert_match /tmp/a '/tmp/*' # match OK
assert_match /tmp/a '/tmp/b*' # match FAILED
用于正则表达式匹配 ([[ ... =~ ... ]]
) 的 assert_rematch
函数也可能有用。
考虑以下代码。如果我删除 eval
而只是写 if ""
它不起作用。是否可以去掉 eval
?
assert () {
if eval "" #Is it possible to get rid of the eval?
then
echo "Assertion OK: \"\""
else
echo "Assertion FAILED: \"\""
fi
}
assert " [[ /tmp/a = /tmp/* ]]"
可以在不使用 eval
的情况下创建一个有用的 assert
函数:
function assert
{
local IFS # Protect "$*" against an unusual IFS value in the caller
if "$@"; then
printf 'Assertion OK: "%s"\n' "$*"
else
printf 'Assertion FAILED: "%s"\n' "$*"
fi
}
示例使用:
assert [ -f /etc/passwd ] # OK
assert [ ! -f /etc/group ] # FAILED
var1='a b'
var2='a b'
var3='-c'
assert [ "$var1" = "$var2" ] # OK
assert [ "$var2" = "$var3" ] # FAILED
assert grep -q '^guest:' /etc/passwd # Maybe OK, maybe FAILED
当命令(</code>)是用户自定义函数(例如<code>dostuff
),Bash内置命令(例如[
或 test
),或外部命令(例如 grep
)。
由于 Bash 处理代码行的方式,如果命令是 Bash reserved word (aka "keyword"). See the accepted answer to What's the difference between shell builtin and shell keyword? 以获得极好的相关信息,该函数将不起作用。特别是,它涵盖了 [ ... ]
和 [[ ... ]]
之间的重要区别。标准 Bash 文档在这方面很差。
[[
是保留字,所以这个不行:
assert [[ /tmp/a = '/tmp/*' ]] # Error: '[[' command not found
由于Bash对[[ ... ]]
里面的代码做了特殊处理,我觉得不可能修改assert
函数让assert [[ ...
在里面工作所有情况。在不使用 eval
的情况下解决该问题的一种方法是在功能重叠的情况下使用 [
而不是 [[
(文件访问测试、简单的字符串比较,...)并使用特殊的 assert_*
函数实现 [[
的特殊功能。例如,此函数测试 (glob) 模式匹配:
function assert_match
{
local -r str=
local -r pat=
# shellcheck disable=SC2053 # (Bad warning about not quoting $pat)
if [[ $str == $pat ]]; then
printf 'assert_match OK: "%s" matches "%s"\n' "$str" "$pat"
else
printf 'assert_match FAILED: "%s" does not match "%s"\n' "$str" "$pat"
fi
}
示例使用:
assert_match /tmp/a '/tmp/*' # match OK
assert_match /tmp/a '/tmp/b*' # match FAILED
用于正则表达式匹配 ([[ ... =~ ... ]]
) 的 assert_rematch
函数也可能有用。