bash 脚本:{dir1,dir2,dir3} 扩展无法按预期从变量中工作,用于选择随机文件

bash 脚本:{dir1,dir2,dir3} 扩展无法按预期从变量中工作,用于选择随机文件

我遇到了一个问题,对于这个简单的脚本(选择一个随机文件):

#!/usr/bin/env bash
set -x
srcDir="/home/user/Desktop/wallPapers/{dir1,dir2,dir3}"
randomFile=$(find "$srcDir" -type f -iname "*.jpg" | shuf -n 1)
printf '[%s]\n' $randomFile
set +x

问题是,虽然我可以在命令行中输入这个(并且工作正常):

find /home/user/Desktop/wallPapers/{dir1,dir2,dir3} -type f -iname "*.jpg"

然后 bash 调试设置命令(set -x 和 +x)告诉我,由于某种原因,bash 不仅用单引号将目录字符串括起来,而且还用单引号替换双引号?

./script.sh
+ srcDir='/home/user/Desktop/wallPapers/{dir1,dir2,dir3}'
++ find '/home/user/Desktop/wallPapers/{dir1,dir2,dir3}' -type f -iname '"*.jpg"'
find: ‘/home/user/Desktop/wallPapers/{dir1,dir2,dir3}’: No such file or directory
+ randomFile=
+ printf '[%s]\n'
[]
+ set +x

我理解,当脚本运行时,bash 看到的内容如下:

find '/home/user/Desktop/wallPapers/{dir1,dir2,dir3}' -type -iname '*.jpg'

这会导致出现“没有此文件或目录”的消息,非常烦人...我不明白,为什么插入这些单引号,我希望使用双引号,就像在命令行上一样...有人可以解释一下吗,我会很高兴,谢谢!

答案1

括号扩展不会发生在变量赋值中,如下所述:

为什么波浪号前缀在赋值之前会扩展,而括号却不会

在其他情况下,引号也会阻止括号扩展。

即使您确实设法srcDir扩展目录列表,在find命令中再次引用它也会导致它被视为单个参数而不是 3 个单独的路径。

在 bash 中执行此操作的正确方法可能是使用数组:

#!/usr/bin/env bash
set -x
srcDir=("/home/user/Desktop/wallPapers/"{dir1,dir2,dir3})
randomFile=$(find "${srcDir[@]}" -type f -iname "*.jpg" | shuf -n 1)
printf '[%s]\n' "$randomFile"
set +x

答案2

正如其他人已经指出的那样,引号阻止了括号扩展。您可以将脚本简化为:

#!/usr/bin/env bash
printf '[%s]\n' "$(find /home/terdon/Desktop/wallPapers/{dir1,dir2,dir3} -type f -iname "*.jpg" | shuf -n 1)"

或者,如果您的文件名可以包含换行符:

#!/usr/bin/env bash
printf '[%s]\n' "$(find /home/terdon/Desktop/wallPapers/{dir1,dir2,dir3} -type f -iname "*.jpg" -print0| shuf -zn 1)"

如果你想要一些可以在任意目录和文件类型上运行的东西,请尝试这个:

#!/usr/bin/env bash

targetFilePattern="$1"
shift
declare -a targetDirs=("$@")
echo "find ${targetDirs[@]} -type f -iname '$targetFilePattern' | shuf -n 1"
randomFile=$(find "${targetDirs[@]}" -type f -iname "$targetFilePattern" | shuf -n 1)
echo "$randomFile"

然后您可以按如下方式运行它:

printRandomFile '*jpg' /home/terdon/Desktop/wallPapers/{dir1,dir2,dir3}

甚至

printRandomFile '*jpg' /home/terdon/Desktop/wallPapers/{dir1,dir2,dir3,'a dir with a space'}

答案3

双引号内不执行括号扩展。某处有一个重复的问题。此外,使用 -printf 标志进行查找,不需要执行命令替换,因此您可以这样做

find /home/user/Desktop/wallPapers/{dir1,dir2,dir3} -type f -iname "*.jpg" -printf '[%f]\n' | shuf -n1

相关内容