「逆順」でブレース展開を適用する


21

たとえば、に{a..c}{1..3}展開されa1 a2 a3 b1 b2 b3 c1 c2 c3ます。

印刷したい場合、それa1 b1 c1 a2 b2 c2 a3 b3 c3を行うための類似の方法はありますか?最も簡単な方法は何ですか?

回答:



10

この特定のケースでは、StéphaneChazelasが提供したオプションが最適だと思います。

一方、より複雑なものを展開する場合、このオプションはうまくスケーリングしません。したがって、これで同じことを実現できます。

$ printf '%s\0' {a..c}{1..3} | sort -zk 1.2,1.2 | tr '\0' ' '

返されるもの:

a1 b1 c1 a2 b2 c2 a3 b3 c3

少し厄介に思えますが、今では、上記のコマンドで2つの文字を変更するだけで、順序を大きく制御できます。例えば:

$ 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番目の展開のすべてを望んでいると仮定し、次に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

a3番目の拡張のすべてが必要だとし、次に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は4番目の拡張のすべてを望んでいると仮定し、次に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真ん中にしたいと仮定し、それから1b、それから2a、そして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

Note_1:通常、この最終展開が引数のリストとして使用される場合、末尾のスペースは問題ではありません。ただし、それを削除する場合は、たとえば| sed 's/ $//'上記のコマンドのいずれかに追加できますまたは| sed 's/ $/\n/'newline

注_2:上記の例では、概念実証の単純化のために2つの要素のサブセット(つまり、{a、b}および {1,2})を使用しました。任意の有限長のサブセットを使用でき、対応するコマンドは同等です。


5

bash、ksh、zsh

(bash、ksh、zsh)で機能する1つのライナー(すべてのシェルが逆順で「ブレース展開」を実行できるわけではありません):

$ 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

yash -o braceexpandリストに追加することもできます。
ステファンシャゼラス

@StéphaneChazelas私は私がすべきかわからない。コマンドはLinuxでyash -o braceexpand -c 'echo {3..1}{c..a}'印刷さ3{c..a} 2{c..a} 1{c..a}れます。完全な「ブレース拡張」ではありません。
アイザック

3
{a..c}1 {a..c}2 {a..c}3

中括弧の展開は{a..c}{1..3}左から右に展開されるため、最初に取得しa{1..3} b{1..3} c{1..3}、次に文字を数字と結合しますa1 a2 a3 b1 b2 b3 c1 c2 c3。希望する順序を取得するには、上記のわずかに長い式を使用する必要があります。


広範囲の「数字」に対してそれを実行したい場合、それはもはや実用的ではありません。
ルーベン・ゴナロ・モロウオ

3
@RUBENGONÇALOMOROUÇOいいえ、そうではありません。もしあなたが広範囲の数値に対してそれをしているなら、二重ループのような代替アプローチを使用することをお勧めします。これは何千もの組み合わせで機能しますが、ブレースは特定のコンテキストで「引数リストが長すぎます」というトリガーを拡張します。
クサラナンダ

2

ループを使用する:

for n in {1..3}; do printf '%s\n' {a..c}"$n"; done

これにより、最初の展開がループされ、2番目の展開で各文字が展開されます。

すべてを1行で出力する必要がある場合は、次を削除できます\n

for n in {1..3}; do printf '%s ' {a..c}"$n"; done

これは末尾の改行を提供しませんが、問題にならないコマンドまたは変数にそれを渡す場合。


1
なぜループソリューションに多くの賛成票がないのですか?
アイザック

私は質問を間違って読んだに違いありません。更新
Jesse_b

2

これは単純なケースで機能し、拡張できますが、すぐに手に負えなくなるでしょう。これがうまくいかないもっと複雑なケースは簡単に構築できます。

ブレース展開の順序を逆にして、文字を交換します。

echo {1..3}{a..c} | sed -E 's/(.)(.)( ?)/\2\1\3/g'

@ムル:おっと。一定。ありがとう。
追って通知があるまで一時停止します。

@Isaac:末尾のスペースを修正しました。
追って通知があるまで一時停止します。

0

1つの簡単な方法は、sortを使用することです(1.2,1.2は、2番目の位置で1つの文字を取得し、同じ場所で終了することを意味します)。

$ for i in {a..c}{1..3}; do echo $i; done|sort -n -k1.2,1.2
a1
b1
c1
a2
b2
c2
a3
b3
c3

それらを1行にしたい場合は、trを次のように使用できます。

$ for i in {a..c}{1..3}; do echo $i; done|sort -n -k1.2,1.2|tr '\n' ' '
a1 b1 c1 a2 b2 c2 a3 b3 c3

-2

以下の方法で完了

for i in {1..10}; do for j in {a..c}; do echo $j$i; done; done| perl -pne "s/\n/ /g"

出力

a1 b1 c1 a2 b2 c2 a3 b3 c3 a4 b4 c4 a5 b5 c5 a6 b6 c6 a7 b7 c7 a8 b8 c8 a9 b9 c9 a10 b10 c10

また考慮してくださいfor i in {1..10}; do for j in {a..c}; do printf '%s ' "$j$i"; done; done;echo
ジェフ・シャラー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.