将globbing的结果分配给Bash中的变量

时间:2012-02-10 15:09:52

标签: bash glob

我的同事Ryan带着他的Bash脚本中的错误来找我,我发现了这个测试的问题:

$ mkdir ryan
$ mkdir ryan/smells-bad
$ FOO=ryan/smells-*
$ echo $FOO
ryan/smells-bad
$ touch $FOO/rotten_eggs
touch: cannot touch `ryan/smells-*/rotten_eggs': No such file or directory

由此我推断,在echo命令期间发生了globbing,而不是在创建变量FOO时。

我们有几个解决方法,按照不正常的降序排列:

touch `echo $FOO`/rotten_eggs

或者:

pushd
cd $FOO
touch rotten_eggs
popd

但两者都不令人满意。我错过了一招吗?

4 个答案:

答案 0 :(得分:34)

问题是如果文件“rotten_eggs”存在,glob只会扩展,因为它包含在glob模式中。你应该使用一个数组。

FOO=( ryan/smells-* )
touch "${FOO[@]/%//rotten_eggs}"

FOO数组包含glob匹配的所有内容。使用%的扩展会将/ rotten_eggs附加到每个元素。

答案 1 :(得分:7)

考虑

for dir in $FOO; do
    touch "$dir/rotten_eggs"
done

请注意,如果glob模式匹配多个路径名,这将touch多个文件。

答案 2 :(得分:5)

预期的代码与分配给变量的glob的结果将是这样的:

$ mkdir ryan
$ mkdir ryan/smells-bad
$ FOO=(ryan/smells-*)
$ echo "${FOO[@]}"
ryan/smells-bad
$ echo "$FOO"
ryan/smells-bad
$ touch "$FOO/rotten_eggs"
$ ls -l "$FOO"
total 0
-rw-r--r-- 1 ryan ryan 0 Mar  1 11:17 rotten_eggs

$FOO实际上是一个数组,但$ FOO也可用于获取数组的第一个元素。

但是,看看glob如何匹配多个文件(因此数组是一个好主意)

$ mkdir ryan/clean
$ FOO=(ryan/*)
$ echo "$FOO"
ryan/clean
$ echo "${FOO[@]}"
ryan/clean ryan/smells-bad

在这些情况下,glob的结果会根据需要分配给变量,而不是在使用时将变量扩展为glob。

当然这意味着变量应该总是在双引号"..."中使用,否则如果文件名本身(glob扩展)中也有*,它会再次变为glob。

e.g。

$ touch ryan/'*ea*'
$ FOO=(ryan/*ea*)
$ echo "${FOO[@]}"
ryan/clean ryan/*ea*
$ echo ${FOO[@]}
ryan/clean ryan/clean ryan/*ea*

答案 3 :(得分:3)

我会这样做:

for FOO in ryan/smells-*; do
  touch "$FOO"/rotten_eggs
done

这种方式$FOO包含实际的目录名,而不是glob模式。但是,如果有多个匹配,它将只包含循环后的最后一个匹配,因此对于这种情况,阵列解决方案可能更好。