如何在Bash脚本中为一个变量赋一个glob表达式?

时间:2008-12-15 17:38:55

标签: bash glob

当在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参考手册(第3.2版)并且看不到任何原因导致文件名通配不发生(我没有将-f传递给shell),或者我可以设置的任何内容确保发生全球化。

8 个答案:

答案 0 :(得分:30)

我认为这是扩展的顺序:

  

扩展的顺序是:brace expansion,代字号扩展,参数,   variable和算术扩展和   命令替换(在一个完成   从左到右的时尚),字   分裂,pathname expansion

因此,如果您的变量被替换,则不再进行大括号扩展。这对我有用:

eval ls $dirs

对eval要非常小心。它将逐字执行这些东西。因此,如果dirs包含f{m,k}t*; some_command,则在ls完成后将执行some_command。它将执行您在当前shell中为eval提供的字符串。它会将/content/dev01 /content/dev02传递给ls,无论它们是否存在。将*放在这些东西后使其成为路径名扩展,它将省略不存在的路径:

dirs=/content/{dev01,dev02}*

我对此并不是百分之百确定,但这对我来说很有意义。

答案 1 :(得分:22)

Here对你要做的事情进行了很好的讨论。

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

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

但是你对结果所做的事情可能会比我想象的要复杂得多。

答案 2 :(得分:8)

这不是文件夹通配,这是大括号扩展。 区别是微妙的,但它存在 - 在文件名通配中你只会收到现有文件,而在大括号扩展中你可以生成任何类型的字符串。

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

答案 3 :(得分:6)

对于那些通过谷歌发现这个问题的人(像我一样),@ Pee和@ feoh的答案是"如何在bash脚本中对变量进行全局解决方案"。

list_of_results=(pattern)

会将与pattern匹配的现有文件名保存到数组list_of_results中。 list_of_results的每个元素都将包含一个文件名,空格和全部。

您可以从{0}开始以"${list_of_results[<index>]}"<index>访问每个结果。您可以将整个列表正确引用为"${list_of_results[@]}"

答案 4 :(得分:2)

我怀疑你需要的是一个数组,但这会限制你进入更新的阶段。它比使用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}"

如果您以任何方式引用括号,它们将不会展开,因此结果将包含大括号并且几乎毫无意义。

答案 5 :(得分:1)

由于你想要glob 文件,你不应该使用大括号扩展。在这种情况下使用大括号扩展是一个反模式,绝对是错误的工具。

你想要的是extended globbing

shopt -s extglob # likely already set in interactive shells

dirs=/content/@(dev01|dev02)
ls $dirs

答案 6 :(得分:0)

ls `echo $dirs` 

在cygwin下工作。

答案 7 :(得分:0)

没有人解决的问题是变量赋值会有所不同。

dirs=/content/{dev01,dev02}

展开方式与

不同
echo /content/{dev01,dev02}

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

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