【问题标题】:Chain commands until variable is not empty or undefined?链接命令直到变量不为空或未定义?
【发布时间】:2015-02-24 02:48:46
【问题描述】:

我正在尝试使用稍后调用的可执行文件填充变量。我知道以下是错误的,因为它正在测试返回值,但我不确定如何正确执行(为方便查看而添加了包装):

CHECKSEC=`which checksec 2>/dev/null` || `which checksec.sh 2>/dev/null` || 
  `ls /usr/local/bin/checksec 2>/dev/null` || `ls /usr/local/bin/checksec.sh 2>/dev/null`

更准确地说,我知道我可以用一堆 if 语句来做到这一点,但我试图避免它,因为它展开成大约 4 或 8 个块:

if [ -z "$CHECKSEC" ]; then
  CHECKSEC=`which checksec 2>/dev/null`
fi
...

if [ -z "$CHECKSEC" ]; then
  echo "Unable to locate checksec. If you have it, be sure its on PATH. If"
  echo "  you need it, you can download it from http://www.trapkit.de/tools/."
  exit 1;
fi

是否可以像我想要的那样链接命令来填充变量? (或者这是“你为什么要这样做”之一?)

如果是这样,我如何链接命令,以便在变量不为空且未定义时停止[特定]处理?

【问题讨论】:

    标签: bash shell command variable-assignment chain


    【解决方案1】:

    蛮力做你似乎想要做的事情是:

    CHECKSEC=$(which checksec 2>/dev/null ||
               which checksec.sh 2>/dev/null || 
               ls /usr/local/bin/checksec 2>/dev/null ||
               ls /usr/local/bin/checksec.sh 2>/dev/null
              )
    

    它不是特别优雅,但它应该可以完成这项工作。使用 $(…) 代替反引号 (`…`) 通常是个好主意。使用起来很诱人:

    CHECKSEC=$( {which checksec || which checksec.sh || 
               ls /usr/local/bin/checksec || ls /usr/local/bin/checksec.sh; } 2>/dev/null)
    

    减少重定向的次数。也很容易考虑:

    CHECKSEC=$( { PATH=$PATH:/usr/local/bin; which checksec || which checksec.sh; } 2>/dev/null)
    

    这样which 将在/usr/local/bin 中查找作为最后的手段。

    【讨论】:

    • 完美,非常感谢。最后一个是最紧凑的,它对负例的测试很好。
    • 严格来说,最后一个版本与ls 版本不太一样;如果它不可执行,它不会在/usr/local/bin 中列出脚本,而ls 变体会。我的怀疑是“没关系”,但您需要注意其中的区别。 (我刚才才注意到。)
    • “我的怀疑是“没关系”......“ - 是的,这是一个错误,我没有意识到正在等待。再次感谢。
    • 你让这看起来简单得令人尴尬。我认为它把问题放在“不知道如何打开计算机的狂热程序员”的某个地方。我应该搜索什么?我选择了标签中使用的明显术语。我得到了单个变量/单个命令命中;我没有拿回优雅的单线。
    • 有时,多年的经验是无可替代的。如果有什么安慰的话,我的第一个想法是 for dir in … 看起来不错,直到我意识到您正在寻找 checksecchecksec.sh,这可以通过嵌套循环处理(一个在目录上,一个在两个脚本名称),但随后您使用 which 向下查看 PATH 和 ls,所以这看起来不太好,但命令和名称上的嵌套循环 - for cmd in which ls; do for name in checksec checksec.sh; do CHECKSEC=$( $cmd $name 2>/dev/null ); [ -n "$CHECKSEC" ] && break; done; done - 可以工作。
    【解决方案2】:

    这会在 $PATH 和 /usr/local/bin 中查找“not_this”、“ls”和“nor_that”。

    应该找到“ls”。

    #!/bin/bash
    
    locate_cmd()
    {
       which "$1" || ls /usr/local/bin/"$1" 2>/dev/null
    }
    
    c=`locate_cmd not_this` || c=`locate_cmd ls` || c=`locate_cmd nor_that` || echo nope
    
    echo cmd=$c
    

    【讨论】:

    • @Hans - 这有点聪明(或者对我来说很聪明,因为我没有考虑过)。我喜欢乔纳森的回答,因为它是一个优雅的单行字。感谢您的帮助。
    • 我也喜欢乔纳森的方式。我经常首先考虑函数,因为它们很容易扩展,但我喜欢他的方法的优雅和简单。
    猜你喜欢
    • 1970-01-01
    • 2020-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-10
    • 2014-04-05
    • 2021-02-21
    • 1970-01-01
    相关资源
    最近更新 更多