- 我想创建 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),不是参数扩展。
在fish
shell 中,列表扩展的行为类似于 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
,命令替换为`cmd
or `{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
或实际上更像fish
csh 样式的大括号扩展。rcexpandparam
并且可以使用语法在每个扩展的基础上启用这种扩展样式$^param
。
也可以在参数扩展中进行命令替换:
$ echo //${(s[;])^"$(locale mon)"}//
//January// //February// //March// //April// //May// //June// //July// //August// //September// //October// //November// //December//
在那里,$(cmd)
命令替换会像大多数其他 shell 一样删除尾随换行符,并且s[;]
此处的参数扩展标志应用于引用的替换分割;
而不是依赖于$IFS
。
zsh/langinfo
zsh 还内置支持获取其模块中的本地化月份名称列表:
$ zmodload zsh/langinfo
$ echo //${(v)^langinfo[(I)MON_<1-12>]}//
//January// //February// //March// //April// //May// //June// //July// //August// //September// //October// //November// //December//
1 让元素包含换行符是可能的,但非常麻烦。