【问题标题】:Test whether a glob has only one match in bash and get it测试一个 glob 在 bash 中是否只有一个匹配项并获取它
【发布时间】:2019-08-22 03:24:12
【问题描述】:

"Test whether a glob has any matches in bash"这个问题的答案很好。

但是,我想知道如何测试一个 glob 在 bash 中是否有只有一个匹配项,以及是否存在分配给一个变量。

我该怎么做?

【问题讨论】:

  • 你想用'*' 匹配什么?文件,其他东西的列表?喜欢cnt=0; for i in *; do myvar="$i"; ((cnt++)); done; [ "$cnt" -ne 1 ] && unset myvar?然后你可以简单地测试[ -n "$myvar" ] && echo "only match was '$myvar'"?
  • @DavidC.Rankin 在这个解决方案中,如果 glob 什么都不匹配,它只会有一个等于 glob 的结果。热的要解决吗?
  • 好收获。 [ "$cnt" -eq 0 ] || [ "$cnt" -ne 1 ] && unset myvar(见编辑)
  • 你的 glob 表达式是什么?就是*还是你有具体的表达方式
  • 更多的可能性是具体的表达方式。 * 或特定表达式有什么区别? @Inian

标签: bash glob


【解决方案1】:

您不需要nullglob。通过一个简单的测试,您可以验证您的 glob 是否扩展为单个条目,或者零个或多个条目:

globexpand=( globexpression )
[[ -e "${globexpand[@]}" ]] && var="$globexpand"

这样做的原因如下:

  1. 如果globexpression 匹配多个文件,使用-e 的测试将失败
  2. 如果globexpression 匹配单个文件,则-e 的测试将匹配
  3. 如果globexpression 不匹配任何文件,globexpand 将把globexpression 作为单个条目保存,并且将通过-e 使测试失败。

因此您不需要任何nullglob 或任何特殊选项。只需确保在此处正确引用以处理带有 特殊 字符的文件名。

另一种方法是使用 find 来计算您的 glob 有多少匹配项:

$ find . -maxdepth 1 -name 'globexpr' -printf c | wc -c

我们使用printf,这样我们就不会遇到可能包含换行符的有趣文件名的问题。话虽如此,现在很简单:

if [[ $(find . -maxdepth 1 -name 'globexpr' -printf c | wc -c) == "1" ]]; then
    # do your magic
else
    # do some other stuff
fi

【讨论】:

    【解决方案2】:

    您可以设置 nullglob 将 glob 扩展为空,如果它们不匹配。如果没有匹配的文件,这将解决 glob 徘徊的问题。

    例如,这里有一个只为函数设置 nullglob 的函数:

    set_one () {
        # Usage:
        #    set_one myvar "some?glob*"
    
        # save nullglob setting (https://stackoverflow.com/a/34957289/2072269),
        # disable field splitting and enable nullgob
        declare nullglob=$(shopt -p nullglob) IFS=
        shopt -s nullglob
    
        # expand second argument as a glob and reset nullglob to saved setting
        declare -a array=($2) 
        eval "$nullglob"
    
        (( ${#array[@]} != 1 )) && return 1
    
        # save first element of array to variable given by first argument
        printf -v "$1" "%s" "$array"
    }
    

    例子:

    $ ls
    a  b  c
    $ set_one foo "*"; echo $? "$foo"
    1
    $ set_one foo "a*"; echo $? "$foo"
    0 a
    $ set_one foo "[d]"; echo $? "$foo"
    1 a  # retains previous value
    

    【讨论】:

      猜你喜欢
      • 2011-02-25
      • 1970-01-01
      • 2022-01-08
      • 2021-10-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多