我的同事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
Run Code Online (Sandbox Code Playgroud)
由此我推断,在echo命令期间发生了globbing,而不是在创建变量FOO时.
我们有一些解决方法,按照不正常的降序排列:
touch `echo $FOO`/rotten_eggs
Run Code Online (Sandbox Code Playgroud)
要么:
pushd
cd $FOO
touch rotten_eggs
popd
Run Code Online (Sandbox Code Playgroud)
但两者都不令人满意.我错过了一招吗?
jor*_*anm 36
问题是如果文件"rotten_eggs"存在,glob只会扩展,因为它包含在glob模式中.你应该使用一个数组.
FOO=( ryan/smells-* )
touch "${FOO[@]/%//rotten_eggs}"
Run Code Online (Sandbox Code Playgroud)
FOO数组包含glob匹配的所有内容.使用%的扩展将/ rotten_eggs附加到每个元素.
考虑
for dir in $FOO; do
touch "$dir/rotten_eggs"
done
Run Code Online (Sandbox Code Playgroud)
请注意,touch如果glob模式匹配多个路径名,则会有多个文件.
预期的代码与分配给变量的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
Run Code Online (Sandbox Code Playgroud)
$FOO 实际上这里是一个数组,但$ FOO也可以获得数组的第一个元素.
但是,看看glob如何匹配多个文件(因此数组是一个好主意)
$ mkdir ryan/clean
$ FOO=(ryan/*)
$ echo "$FOO"
ryan/clean
$ echo "${FOO[@]}"
ryan/clean ryan/smells-bad
Run Code Online (Sandbox Code Playgroud)
在这些情况下,glob的结果根据需要分配给变量,而不是在使用时将变量扩展为glob.
当然这意味着变量应该总是在双引号中使用,"..."否则如果文件名本身(glob扩展)中也有一个*,它会再次变为glob.
例如
$ touch ryan/'*ea*'
$ FOO=(ryan/*ea*)
$ echo "${FOO[@]}"
ryan/clean ryan/*ea*
$ echo ${FOO[@]}
ryan/clean ryan/clean ryan/*ea*
Run Code Online (Sandbox Code Playgroud)