代码之家  ›  专栏  ›  技术社区  ›  kdgregory

如何在Bash脚本中将glob表达式赋给变量?

  •  52
  • kdgregory  · 技术社区  · 17 年前

    当在bash脚本中执行以下两行代码时,“ls”表示文件不存在:

    dirs=/content/{dev01,dev02}
    ls -l $dirs
    

    当我使用-x选项运行脚本时,它似乎是在单引号内传递变量(这将防止全局搜索):

    + dirs=/content/{dev01,dev01}
    + ls -l '/content/{dev01,dev01}'
    ls: /content/{dev01,dev01}: No such file or directory
    

    如果我从交互式shell(无引号)执行“ls”命令,它将返回两个目录。

    我一直在阅读Bash参考手册(v3.2),看不到任何不发生文件名全局化的原因(我没有将-f传递给shell),也看不到我可以设置的任何东西来确保全局化的发生。

    8 回复  |  直到 9 年前
        1
  •  30
  •   Johannes Schaub - litb    17 年前

    我认为这是扩张的顺序:

    扩展的顺序是: brace expansion ,波浪展开,参数, variable 算术展开和 命令替换(在 从左到右时尚),单词 分裂,以及 pathname expansion .

    因此,如果你的变量被替换,括号扩展将不再发生。这对我来说很有效:

    eval ls $dirs
    

    小心eval。它会逐字逐句地执行这些东西。所以如果dirs包含 f{m,k}t*; some_command ,将在ls完成后执行some_command。它将执行您给出的字符串 eval 在当前的shell中。会过去的 /content/dev01 /content/dev02 无论ls是否存在。放 * 在内容使其成为路径名扩展后,它将省略不存在的路径:

    dirs=/content/{dev01,dev02}*
    

    我对此不是百分之百确定,但这对我来说是有道理的。

        2
  •  28
  •   Octavia Togami feoh    6 年前

    Here 这是一个关于你想做什么的精彩讨论。

    简短的回答是,你想要一个数组:

    dirs=(/content/{dev01,dev01})
    

    但我认为,你对结果的处理可能会比你的目标更复杂。

        3
  •  11
  •   cxw    9 年前

    对于像我这样通过谷歌发现这一点的人来说,@Peter和@feoh的答案是“如何在bash脚本中全局变量”的通用解决方案。

    list_of_results=(pattern)
    

    将保存匹配的现有文件名 pattern 进入阵列 list_of_results 每个元素 结果列表 将包含一个文件名、空格和所有内容。

    您可以通过以下方式访问每个结果 "${list_of_results[<index>]}" <index> 从0开始。你可以得到整个列表,正确引用,如下 "${list_of_results[@]}" .

        4
  •  9
  •   Yoni Roit    17 年前

    这不是文件名全局搜索,这是大括号扩展。 这种差异是微妙的,但它确实存在——在文件名全局搜索中,你只会收到现有的文件,而在大括号扩展中,你可以生成任何类型的字符串。

    http://www.gnu.org/software/bash/manual/bashref.html#Brace-Expansion

    http://www.gnu.org/software/bash/manual/bashref.html#Filename-Expansion

    现在,这对我来说是有效的:

    #!/bin/sh
    dirs=`echo ./{dev01,dev02}`
    ls $dirs
    
        5
  •  3
  •   gniourf_gniourf    10 年前

    我怀疑你需要的是一个数组,但这会限制你使用较新的攻击。这比使用eval更省钱。

    dirs=( /"content with spaces"/{dev01,dev02} )
    
    dirs=( /content/{dev01,dev02} )
    ls -l "${dirs[@]}"
    

    /content/{dev01,dev02}
    

    将扩展到:

    "/content/dev01" "/content/dev02"
    

    这些目录的存在与扩展无关。

    当您将变量分配给支架展开时,情况变得不可预测。

    dirs=/content/{dev01,dev02}
    

    可能会变成

    "/content/dev01"
    

    "/content/dev01 /content/dev02"
    

    “/content/dev01”“/content-dev02”
    

    "/content/{dev01,dev02}"
    

    如果你以任何方式引用大括号,它们都不会展开,因此结果将包含大括号,并且大多没有意义。

        6
  •  2
  •   Peter    10 年前

    既然你想环游世界 文件夹, 你不应该使用大括号扩展。在这种情况下使用支架展开是 反模式 而且肯定是这项工作的错误工具。

    你想要的是 extended globbing :

    shopt -s extglob # likely already set in interactive shells
    
    dirs=/content/@(dev01|dev02)
    ls $dirs
    
        7
  •  0
  •   Zsolt Botykai    17 年前

    没有人解决的问题是变量赋值造成了差异。

    dirs=/content/{dev01,dev02}
    

    扩展方式与

    echo /content/{dev01,dev02}
    

    问题是如何将扩展的结果分配给 dirs

    请参阅: How to use Bash substitution in a variable declaration

        8
  •  0
  •   Sam Liddicott    7 年前
    ls `echo $dirs` 
    

    在cygwin下工作。

    推荐文章