49

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

4

8 回答 8

31

我认为这是扩展的顺序:

扩展的顺序是:brace expansion、波浪号扩展、参数 variable和算术扩展和命令替换(以从左到右的方式完成)、分词和pathname expansion.

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

eval ls $dirs

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

dirs=/content/{dev01,dev02}*

我不是 100% 确定这一点,但这对我来说很有意义。

于 2008-12-15T17:51:33.363 回答
28

是对您尝试做的事情的精彩讨论。

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

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

但是你对结果所做的事情可能会比我认为的目标更复杂。

于 2008-12-15T18:00:14.453 回答
13

对于通过谷歌找到这个的人(比如我),@Peter 和@feoh 的答案是“如何在 bash 脚本中全局变量”的一般解决方案。

list_of_results=(pattern)

将匹配的现有文件名保存pattern到数组list_of_results中。的每个元素list_of_results将包含一个文件名、空格和所有元素。

您可以从 0 开始访问每个结果"${list_of_results[<index>]}"<index>您可以获得整个列表,正确引用,如"${list_of_results[@]}".

于 2016-05-24T14:07:21.370 回答
9

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

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
于 2008-12-15T18:10:49.160 回答
3

由于您要 glob文件,因此不应使用大括号扩展。在这种情况下使用大括号扩展是一种反模式,并且绝对是错误的工作工具。

你想要的是扩展通配符

shopt -s extglob # likely already set in interactive shells

dirs=/content/@(dev01|dev02)
ls $dirs
于 2016-03-08T13:16:55.027 回答
2

我怀疑您需要的是一个数组,但这会将您限制在更新的 bash 中。它比使用 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}"

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

于 2016-03-08T12:36:30.147 回答
0
ls `echo $dirs` 

在cygwin下工作。

于 2008-12-15T17:46:49.830 回答
0

没有人解决的问题是变量分配产生了影响。

dirs=/content/{dev01,dev02}

扩展方式不同于

echo /content/{dev01,dev02}

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

请参阅:如何在变量声明中使用 Bash 替换

于 2018-11-07T10:59:28.270 回答