ใช้การขยายรั้งใน "ลำดับย้อนกลับ"


21

ยกตัวอย่างเช่นการขยายตัวไป{a..c}{1..3}a1 a2 a3 b1 b2 b3 c1 c2 c3

ถ้าฉันต้องการที่จะพิมพ์a1 b1 c1 a2 b2 c2 a3 b3 c3มีวิธีการทำเช่นนั้นหรือไม่ วิธีที่ง่ายที่สุดคืออะไร

คำตอบ:


30

คุณสามารถทำได้:

$ eval echo '{a..c}'{1..3}
a1 b1 c1 a2 b2 c2 a3 b3 c3

ซึ่งจะบอกให้เชลล์ประเมินค่า:

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

10

สำหรับกรณีนี้ฉันคิดว่าตัวเลือกที่ได้รับจากStéphane Chazelasเป็นตัวเลือกที่ดีที่สุด

ในทางกลับกันเมื่อคุณขยายสิ่งที่ซับซ้อนมากขึ้นตัวเลือกนี้จะปรับขนาดได้ไม่ดี ดังนั้นคุณสามารถทำสิ่งเดียวกันนี้ได้:

$ 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อยู่ตรงกลางแล้ว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

Note_2 : ในตัวอย่างข้างต้นฉันใช้ชุดย่อยของสององค์ประกอบ (เช่น: {a, b}และ {1,2} ) เพื่อความเรียบง่ายในการพิสูจน์แนวคิด: คุณสามารถใช้ชุดย่อยที่มีความยาว จำกัด ใด ๆ และ คำสั่งที่เกี่ยวข้องจะเทียบเท่า


5

ทุบตี, ksh, zsh

สายการบินเดียวที่ทำงานใน (bash, ksh, zsh) (ไม่ใช่กระสุนทุกตัวที่สามารถทำ "Brace expansion" ในลำดับย้อนกลับ):

$ 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

คุณยังสามารถเพิ่มลงyash -o braceexpandในรายการ
Stéphane Chazelas

@ StéphaneChazelasฉันไม่แน่ใจว่าฉันควร คำสั่งyash -o braceexpand -c 'echo {3..1}{c..a}'พิมพ์3{c..a} 2{c..a} 1{c..a}ใน linux ไม่ใช่ "การขยายรั้ง" แบบเต็ม
Isaac

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ในการรับออเดอร์ที่คุณต้องการคุณจะต้องใช้นิพจน์ที่ยาวกว่าเล็กน้อยด้านบน


หากคุณต้องการทำเพื่อ "ตัวเลข" ที่หลากหลายมันจะไม่เป็นประโยชน์อีกต่อไป
RUBEN GONÇALOMOROUÇO

3
@ RUBENGONÇALOMOROUÇOไม่เป็นเช่นนั้นและถ้าคุณทำเพื่อตัวเลขจำนวนมากฉันขอแนะนำให้ใช้วิธีอื่นเช่นวงคู่ ซึ่งจะใช้ได้กับชุดค่าผสมหลายพันชุดในขณะที่วงเล็บปีกกาขยาย "รายการโต้แย้งยาวเกินไป" ในบริบทบางอย่าง
Kusalananda

2

ใช้วง:

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

สิ่งนี้จะไม่ทำให้คุณขึ้นบรรทัดใหม่ แต่ถ้าคุณส่งไปยังคำสั่งหรือตัวแปรที่ไม่ควรเป็นปัญหา


1
ทำไมคะแนนโหวตมากมายสำหรับโซลูชันวนซ้ำ
Isaac

ฉันต้องอ่านคำถามผิด อัปเดต
Jesse_b

2

ใช้งานได้กับกรณีที่เรียบง่ายของคุณและสามารถขยายได้ แต่มันจะออกไปอย่างรวดเร็ว กรณีที่ซับซ้อนกว่านี้ไม่สามารถใช้งานได้ง่ายในการสร้าง

กลับลำดับของการขยายรั้งจากนั้นสลับอักขระ:

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



0

วิธีการง่าย ๆ อย่างหนึ่งคือการใช้การเรียงลำดับ (1.2,1.2 หมายความว่าคุณรับอักขระหนึ่งตัวที่ตำแหน่งที่สองและสิ้นสุดที่ตำแหน่งเดียวกัน)

$ 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

หากคุณต้องการพวกเขาในหนึ่งบรรทัดคุณสามารถใช้ 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
Jeff Schaller
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.