在Zsh中组合文件测试

时间:2015-01-29 13:10:34

标签: zsh

zsh中测试的最优雅方式是什么,文件是否是可读的常规文件?

我知道我可以做类似

的事情
if [[ -r "$name" && -f "$name" ]]
...

但它需要重复两次“$ name”。我知道我们不能组合条件(-rf $ name),但也许可以使用zsh中的其他一些功能?

顺便说一句,我也考虑过像

这样的东西
if ls ${name}(R.) >/dev/null 2>&1
...

但是在这种情况下,当$ name不符合标准时,shell会抱怨“找不到匹配项”。设置NULL_GLOB也没有帮助,因为它只是用空字符串替换模式,表达式总是为真。

2 个答案:

答案 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.

我觉得这有点矫枉过正。