因此,当我想使用bash列出以多个字母开头的文件时,我可以执行类似echo /home/username/{A,B,C}*
的操作,该操作正确地回显以A
,B
,{{1 }}。
我正在尝试使用脚本内部用户输入的bash变量来做相同的事情,并说几句(例如,脚本名称为C
):
run_user_input.sh
我以var=$1;echo $var;
的身份运行。
但这只是呼应./run_user_input.sh "/home/username/{A,B}*"
。
请注意,/home/username/{A,B}*
仍然可以正常工作。
如何解决?
答案 0 :(得分:1)
在双引号中,仅扩展了几处内容:最重要的是参数和命令替换,但没有文件名(也没有大括号扩展),因此双引号内的*
始终是文字。
然后,在作业的右侧,也没有 文件名和括号扩展,因此var=*
会将文字*
放入{{1 }},即使没有引号。您的最后一个示例“有效”仅是因为您没有引用var
的扩展名,而实际上包含了$var
。
方法是使用数组:
/home/username/A*
这将同时执行大括号和文件名扩展,并且数组元素将每个包含一个文件名,并正确转义了空格和glob字符。用正确的引号访问它们:
fnames=(/home/username/{A,B,C}*)
例如,为您提供第一个文件名。
如果将模式作为参数提供给脚本,则可能无法使用echo "${fnames[0]}"
:
eval
有关pattern=$1
eval fnames=("$pattern")
的{{3}} 。如果您将以下内容作为模式提供:
eval
pattern='x); echo pwnd #'
会将行扩展为
eval
并实际运行注入的命令,这可能不仅仅只是回声。
可悲的是,健壮的方法
fnames=(x); echo pwnd #)
不起作用,因为它会阻止扩展。
为避免这种情况,建议您重写脚本以接受多个参数,然后让Shell进行扩展:
eval "$(printf 'fnames=(%q)' "$pattern")"
在脚本中类似
./yourscript path/to/dir/{A,B}*
(与for file; do <something>; done
相同)。现在您可以享受shell扩展带来的好处,而没有for file in "$@"; do <something>; done
的缺点了。