![bash、ksh、zsh](https://linux22.com/image/155793/bash%E3%80%81ksh%E3%80%81zsh.png)
例如{a..c}{1..3}
扩展到a1 a2 a3 b1 b2 b3 c1 c2 c3
.
如果我想打印a1 b1 c1 a2 b2 c2 a3 b3 c3
,有类似的方法吗?最简单的方法是什么?
答案1
你可以这样做:
$ eval echo '{a..c}'{1..3}
a1 b1 c1 a2 b2 c2 a3 b3 c3
然后告诉 shell 进行评估:
echo {a..c}1 {a..c}2 {a..c}3
答案2
对于这种特殊情况,我认为给出的选项斯蒂芬·查泽拉斯是最好的。
另一方面,当您扩展更复杂的事物时,此选项不能很好地扩展。因此,您可以通过以下方式实现相同的目的:
$ printf '%s\0' {a..c}{1..3} | sort -zk 1.2,1.2 | tr '\0' ' '
返回:
a1 b1 c1 a2 b2 c2 a3 b3 c3
看起来有点乱,但现在,我对顺序有了很大的控制权,只需更改上面命令中的两个字符即可;例如:
$ echo {a..b}{1..2}{a..b}{1..2}
这将扩展到:
a1a1 a1a2 a1b1 a1b2 a2a1 a2a2 a2b1 a2b2 b1a1 b1a2 b1b1 b1b2 b2a1 b2a2 b2b1 b2b2
假设我想要第二个扩展中的所有内容1
,那么2
:
$ printf '%s\0' {a..b}{1..2}{a..b}{1..2} | sort -zk 1.2,1.2 | tr '\0' ' '
a1a1 a1a2 a1b1 a1b2 b1a1 b1a2 b1b1 b1b2 a2a1 a2a2 a2b1 a2b2 b2a1 b2a2 b2b1 b2b2
假设我想要第三个扩展中的所有内容a
,那么b
:
$ printf '%s\0' {a..b}{1..2}{a..b}{1..2} | sort -zk 1.3,1.3 | tr '\0' ' '
a1a1 a1a2 a2a1 a2a2 b1a1 b1a2 b2a1 b2a2 a1b1 a1b2 a2b1 a2b2 b1b1 b1b2 b2b1 b2b2
假设我想要第四个扩展中的所有内容1
,那么2
:
$ printf '%s\0' {a..b}{1..2}{a..b}{1..2} | sort -zk 1.4,1.4 | tr '\0' ' '
a1a1 a1b1 a2a1 a2b1 b1a1 b1b1 b2a1 b2b1 a1a2 a1b2 a2a2 a2b2 b1a2 b1b2 b2a2 b2b2
假设我想要所有1a
中间的 then 1b
, then 2a
, then 2b
:
$ printf '%s\0' {a..b}{1..2}{a..b}{1..2} | sort -zk 1.2,1.3 | tr '\0' ' '
a1a1 a1a2 b1a1 b1a2 a1b1 a1b2 b1b1 b1b2 a2a1 a2a2 b2a1 b2a2 a2b1 a2b2 b2b1 b2b2
您甚至可以同样轻松地反转上述扩展中的任何顺序,只需r
在前一个命令中添加一个即可;例如最后一个:
$ printf '%s\0' {a..b}{1..2}{a..b}{1..2} | sort -rzk 1.2,1.3 | tr '\0' ' '
b2b2 b2b1 a2b2 a2b1 b2a2 b2a1 a2a2 a2a1 b1b2 b1b1 a1b2 a1b1 b1a2 b1a1 a1a2 a1a1
注_1:通常,如果最终扩展将用作参数列表,则尾随空格不是问题;但如果你想摆脱它,你可以添加,到上面的任何命令,例如| sed 's/ $//'
;或者甚至| sed 's/ $/\n/'
,将尾随空格更改为newline
笔记2:在上面的示例中,我使用了两个元素的子集(即:{a,b}和{1,2})只是为了概念证明的简单性:您可以使用任何有限长度的子集,并且相应的命令将是可比较的。
答案3
bash、ksh、zsh
一个适用于(bash、ksh、zsh)的单行程序(并非所有 shell 都可以按相反顺序执行“大括号扩展”):
$ echo {3..1}{c..a} | rev
a1 b1 c1 a2 b2 c2 a3 b3 c3
使用的替代方案eval
(仍然适用于 bash、ksh、zsh,并且可能更神秘)是:
$ eval echo '{a..c}'{1..3}
a1 b1 c1 a2 b2 c2 a3 b3 c3
要了解发生的情况,请替换eval
为echo
:
$ echo echo '{a..c}'{1..3}
echo {a..c}1 {a..c}2 {a..c}3
执行的命令(在 eval 扩展之后)实际上是echo {a..c}1 {a..c}2 {a..c}3
.它可以根据您的需要进行扩展。
所有贝壳
有几个外壳没有“大括号扩展”,因此不可能将其用于“所有外壳”。我们需要一个循环(带有尾随空格):
$ for i in 1 2 3; do for j in a b c; do printf "%s%s " "$j" "$i"; done; done; echo
a1 b1 c1 a2 b2 c2 a3 b3 c3
如果您必须不添加尾随空格:
s=""
for i in 1 2 3; do
for j in a b c; do
printf "%s%s%s" "$s" "$j" "$i"
s=" "
done
done
echo
印刷
a1 b1 c1 a2 b2 c2 a3 b3 c3
如果您需要对许多值执行此操作,我们需要使用类似于大括号扩展的方法来生成数字列表$(seq 10)
。并且,由于 seq 无法生成字母列表,我们需要将生成的数字转换为 ascii:
s=""
for i in $(seq 4); do
for j in $(seq 5); do
printf "%s\\$(printf %03o $((96+j)))%s" "$s" "$i"
s=" "
done
done
echo
印刷:
a1 b1 c1 d1 e1 a2 b2 c2 d2 e2 a3 b3 c3 d3 e3 a4 b4 c4 d4 e4
答案4
使用循环:
for n in {1..3}; do printf '%s\n' {a..c}"$n"; done
这将循环执行您的第一个扩展,然后使用第二个扩展扩展每个字符。
如果您需要将所有输出放在一行上,您可以删除\n
:
for n in {1..3}; do printf '%s ' {a..c}"$n"; done
这不会给您一个尾随换行符,但如果您将其传递给命令或变量,那么这应该不是问题。