bash、ksh、zsh

bash、ksh、zsh

例如{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

要了解发生的情况,请替换evalecho

$ 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

这不会给您一个尾随换行符,但如果您将其传递给命令或变量,那么这应该不是问题。

相关内容