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

问题描述 投票:27回答:4

我的同事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

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

bash glob
4个回答
34
投票

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

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

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


7
投票

考虑

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

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


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。

EG

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

3
投票

我会这样做:

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

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

© www.soinside.com 2019 - 2024. All rights reserved.