ยกตัวอย่างเช่นการขยายตัวไป{a..c}{1..3}
a1 a2 a3 b1 b2 b3 c1 c2 c3
ถ้าฉันต้องการที่จะพิมพ์a1 b1 c1 a2 b2 c2 a3 b3 c3
มีวิธีการทำเช่นนั้นหรือไม่ วิธีที่ง่ายที่สุดคืออะไร
ยกตัวอย่างเช่นการขยายตัวไป{a..c}{1..3}
a1 a2 a3 b1 b2 b3 c1 c2 c3
ถ้าฉันต้องการที่จะพิมพ์a1 b1 c1 a2 b2 c2 a3 b3 c3
มีวิธีการทำเช่นนั้นหรือไม่ วิธีที่ง่ายที่สุดคืออะไร
คำตอบ:
คุณสามารถทำได้:
$ 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
สำหรับกรณีนี้ฉันคิดว่าตัวเลือกที่ได้รับจาก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} ) เพื่อความเรียบง่ายในการพิสูจน์แนวคิด: คุณสามารถใช้ชุดย่อยที่มีความยาว จำกัด ใด ๆ และ คำสั่งที่เกี่ยวข้องจะเทียบเท่า
สายการบินเดียวที่ทำงานใน (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 -c 'echo {3..1}{c..a}'
พิมพ์3{c..a} 2{c..a} 1{c..a}
ใน linux ไม่ใช่ "การขยายรั้ง" แบบเต็ม
{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
ในการรับออเดอร์ที่คุณต้องการคุณจะต้องใช้นิพจน์ที่ยาวกว่าเล็กน้อยด้านบน
ใช้วง:
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
สิ่งนี้จะไม่ทำให้คุณขึ้นบรรทัดใหม่ แต่ถ้าคุณส่งไปยังคำสั่งหรือตัวแปรที่ไม่ควรเป็นปัญหา
ใช้งานได้กับกรณีที่เรียบง่ายของคุณและสามารถขยายได้ แต่มันจะออกไปอย่างรวดเร็ว กรณีที่ซับซ้อนกว่านี้ไม่สามารถใช้งานได้ง่ายในการสร้าง
กลับลำดับของการขยายรั้งจากนั้นสลับอักขระ:
echo {1..3}{a..c} | sed -E 's/(.)(.)( ?)/\2\1\3/g'
วิธีการง่าย ๆ อย่างหนึ่งคือการใช้การเรียงลำดับ (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
ทำตามวิธีด้านล่าง
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
yash -o braceexpand
ในรายการ