Ví dụ {a..c}{1..3}
mở rộng đến a1 a2 a3 b1 b2 b3 c1 c2 c3
.
Nếu tôi muốn in a1 b1 c1 a2 b2 c2 a3 b3 c3
, có một cách tương tự để làm điều đó? Cách đơn giản nhất là gì?
Ví dụ {a..c}{1..3}
mở rộng đến a1 a2 a3 b1 b2 b3 c1 c2 c3
.
Nếu tôi muốn in a1 b1 c1 a2 b2 c2 a3 b3 c3
, có một cách tương tự để làm điều đó? Cách đơn giản nhất là gì?
Câu trả lời:
Bạn có thể làm:
$ eval echo '{a..c}'{1..3}
a1 b1 c1 a2 b2 c2 a3 b3 c3
Mà sau đó nói với vỏ để đánh giá:
echo {a..c}1 {a..c}2 {a..c}3
Đối với trường hợp cụ thể này, tôi nghĩ rằng tùy chọn được đưa ra bởi Stéphane Chazelas là lựa chọn tốt nhất.
Mặt khác, khi bạn mở rộng những thứ phức tạp hơn, tùy chọn này không mở rộng tốt. Vì vậy, bạn có thể đạt được điều tương tự với điều này:
$ printf '%s\0' {a..c}{1..3} | sort -zk 1.2,1.2 | tr '\0' ' '
Trả về:
a1 b1 c1 a2 b2 c2 a3 b3 c3
Có vẻ hơi lộn xộn, nhưng bây giờ, tôi có một sự kiểm soát lớn theo thứ tự, chỉ cần thay đổi hai ký tự trong lệnh trên; ví dụ:
$ echo {a..b}{1..2}{a..b}{1..2}
điều này sẽ mở rộng đến:
a1a1 a1a2 a1b1 a1b2 a2a1 a2a2 a2b1 a2b2 b1a1 b1a2 b1b1 b1b2 b2a1 b2a2 b2b1 b2b2
Giả sử tôi muốn tất cả 1
trong bản mở rộng thứ hai, sau đó 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
Giả sử tôi muốn tất cả a
trong bản mở rộng thứ ba, sau đó 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
Giả sử tôi muốn tất cả các 1
bản mở rộng thứ tư, sau đó 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
Giả sử tôi muốn tất cả 1a
ở giữa, sau 1b
đó 2a
, sau đó 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
Bạn thậm chí có thể dễ dàng, đảo ngược mọi thứ tự trong các mở rộng ở trên, chỉ cần thêm một r
lệnh vào trước đó; ví dụ: cái cuối cùng:
$ 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
Lưu ý_1 : thông thường, nếu bản mở rộng cuối cùng này sẽ được sử dụng làm danh sách các đối số, không gian dấu không phải là vấn đề; nhưng nếu bạn muốn loại bỏ nó, bạn có thể thêm vào bất kỳ lệnh nào ở trên| sed 's/ $//'
; hoặc thậm chí| sed 's/ $/\n/'
, để thay đổi không gian đó cho mộtnewline
Lưu ý_2 : Trong các ví dụ ở trên, tôi đã sử dụng các tập hợp con của hai phần tử (ví dụ: {a, b} và {1,2} ) chỉ để đơn giản trong chứng minh khái niệm: bạn có thể sử dụng các tập hợp con có độ dài hữu hạn và lệnh tương ứng, sẽ được so sánh.
Một lớp lót hoạt động trong (bash, ksh, zsh) (không phải tất cả các shell đều có thể thực hiện "Mở rộng cú đúp" theo thứ tự ngược lại):
$ echo {3..1}{c..a} | rev
a1 b1 c1 a2 b2 c2 a3 b3 c3
Một thay thế sử dụng eval
(vẫn còn cho bash, ksh, zsh và có thể khó hiểu hơn) là:
$ eval echo '{a..c}'{1..3}
a1 b1 c1 a2 b2 c2 a3 b3 c3
Để hiểu những gì xảy ra, thay thế eval
bằng echo
:
$ echo echo '{a..c}'{1..3}
echo {a..c}1 {a..c}2 {a..c}3
Lệnh được thực thi (sau khi mở rộng eval) là thực sự echo {a..c}1 {a..c}2 {a..c}3
. Mà mở rộng như bạn muốn / cần.
Có một số vỏ mà không có "mở rộng nẹp", vì vậy, không thể sử dụng nó cho "tất cả các vỏ". Chúng ta cần một vòng lặp (với một khoảng trắng ở cuối):
$ 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
Nếu bạn không có dấu cách được thêm vào:
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
Bản in
a1 b1 c1 a2 b2 c2 a3 b3 c3
NẾU bạn cần làm điều này cho nhiều giá trị, chúng ta cần sử dụng một cái gì đó tương tự như mở rộng dấu ngoặc để tạo danh sách các số $(seq 10)
. Và, vì seq không thể tạo danh sách các chữ cái, chúng tôi cần chuyển đổi thành ascii các số được tạo:
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
in:
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}'
in 3{c..a} 2{c..a} 1{c..a}
trong linux. Không phải là một "mở rộng cú đúp" đầy đủ.
{a..c}1 {a..c}2 {a..c}3
Các mở rộng dấu ngoặc trong {a..c}{1..3}
được mở rộng từ trái sang phải, vì vậy trước tiên bạn nhận được a{1..3} b{1..3} c{1..3}
và sau đó các chữ cái được kết hợp với các số thành a1 a2 a3 b1 b2 b3 c1 c2 c3
. Để có được thứ tự bạn muốn, bạn sẽ phải sử dụng biểu thức dài hơn một chút ở trên.
Sử dụng một vòng lặp:
for n in {1..3}; do printf '%s\n' {a..c}"$n"; done
Điều này sẽ lặp qua lần mở rộng đầu tiên của bạn và sau đó mở rộng từng ký tự với lần thứ hai.
Nếu bạn cần tất cả đầu ra trên một dòng, bạn có thể xóa \n
:
for n in {1..3}; do printf '%s ' {a..c}"$n"; done
Điều này sẽ không cung cấp cho bạn một dòng mới nhưng nếu bạn chuyển nó đến một lệnh hoặc biến không phải là một vấn đề.
Điều này làm việc cho trường hợp đơn giản của bạn và có thể được mở rộng, nhưng nó sẽ nhanh chóng ra khỏi tầm tay. Các trường hợp phức tạp hơn mà điều này sẽ không hoạt động dễ dàng để xây dựng.
Đảo ngược thứ tự mở rộng của nẹp, sau đó hoán đổi các ký tự:
echo {1..3}{a..c} | sed -E 's/(.)(.)( ?)/\2\1\3/g'
Một phương pháp đơn giản sẽ là sử dụng sort (1.2,1.2 có nghĩa là bạn lấy một ký tự ở vị trí thứ hai và kết thúc tại cùng một vị trí).
$ 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
Nếu bạn muốn chúng trong một dòng, bạn có thể sử dụng tr như vậy:
$ 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
Thực hiện theo phương pháp dưới đây
for i in {1..10}; do for j in {a..c}; do echo $j$i; done; done| perl -pne "s/\n/ /g"
đầu ra
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
vào danh sách.