我见过很多与此类似的问题,但没有一个完全相同。
我有一个文件目录,我想使用通配符扩展将其作为单个双引号参数传递给命令。
文件
a.ext
b.ext
c.ext
所需用途
command --flag "a.ext b.ext c.ext"
目前,我正在使用command --flag $(echo \"$(echo ./*.ext)\")
,但这不起作用,而且看起来也不必要地复杂。有没有一种简单的方法可以做到这一点?
答案1
如果您想连接由 SPC 字符扩展的 glob 产生的文件名,您可以将它们存储在位置参数中并用于"$*"
进行连接:
set -- ./*.ext
IFS=' ' # SPC is the first character of $IFS by default, we're setting it
# here in case that code is called in a context where it has been
# modified before.
files_joined_with_SPC="$*"
cmd --flag "$files_joined_with_SPC"
或者:
cmd --flag "$*"
当然直接(尽管更容易忘记它取决于 的当前值这一事实$IFS
)。
以上是标准的 POSIXsh
语法。在zsh
// ksh93
// bash
/中mksh
,yash
您还可以使用数组代替位置参数:
files=(./*.ext)
IFS=' '; files_joined_with_SPC="${files[*]}"
通过zsh
,您还可以使用:
files=(./*.ext)
cmd --flag "${(j[ ])files}"
或者使用匿名函数:
(){ cmd --flag "${(j[ ])argv}"; } ./*.ext
我们明确请求j
使用 SPC,而不必依赖像 之类的全局参数$IFS
。
现在,请注意 SPC 与文件路径中的任何字符一样有效。文件路径中除 NUL 之外的任何字符都有效(实际上任何字符)字节值但在大多数系统上为 0,这些字节甚至不必形成有效字符),但 NUL 不能在参数中传递给以下命令:被处决。
你不说那是什么command
是(顺便说一下,command
这是标准 shell 内置命令的名称,我更喜欢用作cmd
占位符),但如果这cmd --flag list
意味着接受任何文件名列表(以 SPC 分隔),则它们必须有一种方法让用户指定SPC
在文件名中。
这可能是cmd --flag 'with\ space.ext other.ext'
或cmd --flag 'with%20space.ext other.ext
、cmd --flag 'with\040space.ext other.ext'
等等。
在这种情况下,在构建 的参数时cmd --flag
,您可能必须逃脱在将文件名与 SPC 连接之前,先将文件名中的 SPC(以及可能的\
字符)包含在内。%
在ksh93
// zsh
/中bash
,yash
可以通过以下方式完成:
escaped_files=("${files[@]//\\/\\\\}") # \ escaped as \\
escaped_files=("{files[@]// /\\ }") # SPC escaped as \SPC
# more characters may need to be escaped such as other whitespace
# or quoting characters, depending on the exact syntax expected by
# cmd for the --flag option.
IFS=' '; escaped_files_joined_with_SPC="$*"
cmd -- flag "$escaped_files_joined_with_SPC"
(尽管要注意使用 GB18030、BIG5 等字符编码的语言环境,其中某些字符包含反斜杠编码(字节 0x5c)。您的 shell 可能不会转义这些 0x5c 字节,但cmd --flag
如果不解码,可能仍会将它们视为反斜杠根据语言环境的字符集的参数)。
更可靠/更方便的命令方式来获取列表文件名的方法是将它们作为单独的参数(因此不作为选项的参数),或作为cmd --flag 'file 1.ext' --flag 'file 2.ext'...
.
答案2
要获取一个带引号的字符串中的所有文件名:
command --flag "$(echo ./*.ext)"
如您所知,这仅适用于简单的文件名。这意味着文件名中没有空格。根据 的值xpg_echo
,它也可能意味着没有反斜杠(提示:善行)。
答案3
设置 glob 扩展文件的 for 循环。让名为 var 的 shell 变量作为文件名的容器。在每次迭代中我们都会更新 shell 变量 var
var=
for f in *.ext; do var=${var-}${var:+ }$f; done
your_command --flag "$var"