如何将参数扩展与命令替换一起使用?

如何将参数扩展与命令替换一起使用?
  • 我想创建 12 个以月份命名的目录。因此,我尝试使用管道locale来获取月份名称,用tr逗号分隔它们,然后用大括号括起来并传递给mkdir.但整体被视为一根弦。有办法避免这种情况吗?
16:07: temp ⧲ mkdir {$(locale mon | tr \; ,)}

16:18: temp ⧲ ls -lh
total 4.0K
drwxr-xr-x. 2 john john 4.0K Dec 11 16:18 {January,February,March,April,May,June,July,August,September,October,November,December}

16:18: temp ⧲ 

答案1

使用 ”;”作为输入字段分隔符分割输出locale man

IFS=';'
mkdir -- $(locale mon)

答案2

您不能像这样使用大括号扩展,xargs而是使用:

locale mon | tr ';' '\n' | xargs mkdir

答案3

通常,您不会像这样将大括号扩展与命令替换(或参数扩展)一起使用。

在 Bash 中不行,因为 Bash 扩展大括号扩展非常不方便第一的;而在 zsh 中则不然,因为虽然 zsh 在大括号扩展之前扩展命令替换和参数扩展,但它需要文字大括号和逗号来进行大括号扩展。

不过,您可以这样做 ksh,因为它似乎并不关心逗号和大括号来自哪里。这就像您尝试的那样工作:

ksh$ mkdir {$(locale mon | tr \; ,)}

比较:

 # this brace expands
ksh$ x=abc,def; echo {$x}
abc def

 # increasingly silly, but also expands
ksh$ x="foo{abc" y=",def}"; echo $x$y
fooabc foodef

 # it doesn't work like that in zsh
zsh% x=abc,def; echo {$x}
{abc,def}

 # this works sensibly though, the comma is just part of the data
zsh% x=abc,def y=ghi; echo {$x,$y}xyz
abc,defxyz ghixyz

 # this also makes sense
zsh% a=1 b=4; echo {$a..$b}
1 2 3 4

 # but Bash just fails with it
bash$ a=1 b=4; echo {$a..$b}
{1..4}

不过,如果你真的想要,你当然可以使用 来做到这一点eval,即使是在 Bash 中:

eval "mkdir {$(locale mon | tr \; ,)}"

尽管这会带来有关处理不受信任的输入的所有常见警告,所以您最好只使用其他答案中的解决方案。

答案4

{x,y}大括号扩展(最初来自 70 年代的 csh),不是参数扩展

fishshell 中,列表扩展的行为类似于 csh 参数扩展。

例如:

> echo //(string split -- ';' (locale mon))//
//January// //February// //March// //April// //May// //June// //July// //August// //September// //October// //November// //December//

与...一样:

% echo //{January,February,...}//
//January// //February// //...//

在 csh(或从 csh 复制该功能的 shell)中。

在 中fish,命令替换是 with(cmd)而不是`cmd`Bourne/csh 或$(cmd)类似 Korn 的 shell。

在本例中 rc shell 中也是如此:

; echo //^``(';
'){locale mon}^//
//January// //February// //March// //April// //May// //June// //July// //August// //September// //October// //November// //December//

在 中rc,命令替换为`cmdor `{more complex cmd},并且有一种``(seps){cmd}形式可以指定分隔符列表而不是$ifs。您会注意到这里我们同时使用;和 换行符,因为我们不希望末尾的换行符输出locale mon包含在最后一个元素中。fish在换行符上进行分割,并string split输出每个元素每行一个

它与 的扩展或 csh 样式大括号扩展的不同之处在于fish,当两个元素数量不是 1 的列表连接在一起时:

$ rc -c 'echo `{seq 3}^`{seq 3}'
11 22 33
$ fish -c 'echo (seq 3)(seq 3)'
11 12 13 21 22 23 31 32 33
$ fish -c 'echo (seq 2)(seq 3)'
11 12 13 21 22 23
$ rc -c 'echo `{seq 2}^`{seq 3}'
rc: line 0: bad concatenation

当该选项打开时,zsh 的参数扩展的行为类似于rc或实际上更像fishcsh 样式的大括号扩展。rcexpandparam并且可以使用语法在每个扩展的基础上启用这种扩展样式$^param

也可以在参数扩展中进行命令替换:

$ echo //${(s[;])^"$(locale mon)"}//
//January// //February// //March// //April// //May// //June// //July// //August// //September// //October// //November// //December//

在那里,$(cmd)命令替换会像大多数其他 shell 一样删除尾随换行符,并且s[;]此处的参数扩展标志应用于引用的替换分割;而不是依赖于$IFS

zsh/langinfozsh 还内置支持获取其模块中的本地化月份名称列表:

$ zmodload zsh/langinfo
$ echo //${(v)^langinfo[(I)MON_<1-12>]}//
//January// //February// //March// //April// //May// //June// //July// //August// //September// //October// //November// //December//

1 让元素包含换行符是可能的,但非常麻烦。

相关内容