我正在尝试选择作为参数传递的一组目录中的文件,其中包含以下内容:
${@/%/*}
然而,这并不理想,因为带有空格的路径将被破坏,并且引用参数扩展将依次停止文件名扩展。能否有一个满意的解决方案?
PS:我知道你应该用来find -maxdepth
执行此操作,但我很好奇为什么将参数扩展与通配符混合起来看起来如此困难。
答案1
你总是可以这样做:
IFS= # don't split
files=(${@/%/*}) # use split+glob upon expansion with split disabled
但是,如果"$@"
包含通配符,它们将被如此解释。此外,对于每个不匹配的 glob,您最终都会得到未展开的模式。
您可以使用循环和nullglob
选项来解决这些问题:
shopt -s nullglob
files=()
for arg do files+=("$arg"*); done
或者您可以使用zsh
代替bash
并使用:
files=($^argv*(N))
$^array
打开rcexpandparam
的一次扩展选项$array
。在rc
shell 中(shell 中也是如此fish
),$array*
where$array
包含两个元素a
并b
扩展为a*
, b*
,所以这里就像 do files=($argv[1]*(N) $argv[2]*(N)...)
($argv[1]
与 相同$1
,只是更冗长)。(N)
它本身是一个 glob 限定符,用于打开nullglob
该 glob 的行为。
在fish
shell 中,那就是:
set files $argv*
as在参数中fish
启用nullglob
类似行为,set
并与 类似地扩展数组rc
。但请注意,语法与more thanfish
的语法完全不同。bash
zsh
请注意,这些旨在按照您的意愿扩展"$1"*
, ... 全局。如果您实际上的意思是... globs,作为您的"$2"*
${@/%/*}
"$1"/*
"%2"/*
作为参数传递的一组目录中的文件建议,您需要 在上面的代码片段中使用${@/%/\/*}
, , "$arg"/*
, $^argv/*(N)
。$argv*
答案2
用反斜杠+字符替换其他通配符。用反斜杠+字符替换空白字符或(更稳健)设置IFS
为空字符串。请记住首先转义反斜杠,这样您就不会最终重新转义先前转义步骤产生的反斜杠。但如果没有什么可转义的,就不要转义任何内容,因为反斜杠只有在存在通配符时才是特殊的。
nullglob
如果没有匹配项,则设置该选项以获取空列表,而不是未展开的模式。在函数中执行此操作,并安排将更改保留到 shell 选项和IFS
本地。
最低限度的测试:
function set_patterns {
typeset restore_shopt=$(shopt -p nullglob)
shopt -s nullglob
typeset IFS=
typeset x
patterns=()
for x; do
if [[ "$x" == *[*?[]* ]]; then
x="${x//\\/\\\\}"
x="${x//\*/\\*}"
x="${x//\?/\\?}"
x="${x//\[/\\[}"
fi
x="${x//%/*}"
patterns+=($x)
done
eval "$restore_shopt"
}