zsh中测试的最优雅方式是什么,文件是否是可读的常规文件?
我知道我可以做类似
的事情if [[ -r "$name" && -f "$name" ]]
...
但它需要重复两次“$ name”。我知道我们不能组合条件(-rf $ name),但也许可以使用zsh中的其他一些功能?
顺便说一句,我也考虑过像
这样的东西if ls ${name}(R.) >/dev/null 2>&1
...
但是在这种情况下,当$ name不符合标准时,shell会抱怨“找不到匹配项”。设置NULL_GLOB也没有帮助,因为它只是用空字符串替换模式,表达式总是为真。
答案 0 :(得分:2)
在非常新版本的 zsh (适用于5.0.7,但不适用于5.0.5)中,你可以这样做
setopt EXTENDED_GLOB
if [[ -n $name(#qNR.) ]]
...
$name(#qNR.)
匹配名称为$name
且可读(R
)和常规(.
)的文件。 N
为此匹配启用NULL_GLOB
。也就是说,如果没有文件与模式匹配,则它不会产生错误,但会从参数列表中删除。 -n
检查匹配是否实际上是非空的。启用EXTENDED_GLOB
类型的扩展globbing需要(#q...)
,因为括号通常在条件表达式中具有不同的含义([[ ... ]]
)。
尽管如此,我确实可以写一些仅使用$name
一次的内容,但我会反对它。它比原始解决方案更复杂,因此对于下一个阅读它的人来说更难理解(即需要思考)(你的未来自我算作"下一个人"最多半年后)。至少这个解决方案只适用于 zsh ,只适用于新版本,而原始版本将在 bash 上保持不变。
答案 1 :(得分:2)
如上所述,如何制作小(?)shell函数?
tests-raw () {
setopt localoptions no_ksharrays
local then="$1"; shift
local f="${@[-1]}" t=
local -i ret=0
set -- "${@[1,-2]}"
for t in ${@[@]}; do
if test "$t" "$f"; then
ret=$?
"$then"
else
return $?
fi
done
return ret
}
and () tests-raw continue "${@[@]}";
or () tests-raw break "${@[@]}";
# examples
name=/dev/null
if and -r -c "$name"; then
echo 'Ok, it is a readable+character special file.'
fi
#>> Ok, it is...
and -r -f ~/.zshrc ; echo $? #>> 0
or -r -d ~/.zshrc ; echo $? #>> 0
and -r -d ~/.zshrc ; echo $? #>> 1
# It could be `and -rd ~/.zshrc` possible.
我觉得这有点矫枉过正。