Kịch bản Shell cho cú pháp vòng lặp


190

Tôi đã nhận được những điều sau đây để làm việc:

for i in {2..10}
do
    echo "output: $i"
done

Nó tạo ra một loạt các dòng output: 2, output: 3, vân vân.

Tuy nhiên, cố gắng chạy như sau:

max=10
for i in {2..$max}
do
    echo "$i"
done

sản xuất như sau:

output: {2..10}

Làm thế nào tôi có thể khiến trình biên dịch nhận ra nó nên coi $ max là đầu kia của mảng chứ không phải là một phần của chuỗi?


2
bạn đang sử dụng hệ thống và vỏ nào? Loại hệ thống ngớ ngẩn nào có sh hoặc bash, nhưng không có seq, coreutil?
whatsisname

11
FreeBSD không.
Nietzche-jou

echo "$inên echo "$i"- sẽ không khắc phục vấn đề, mặc dù.
Dave Jarvis

Phong cách nhỏ nit: Tôi thường thấy dothentừ khóa trên cùng một dòng như forif, tương ứng. Ví dụ:for i in {2..10}; do
một mọt sách được trả tiền vào

Câu trả lời:


232

Mở rộng cú đúp , {x..y} được thực hiện trước các lần mở rộng khác, vì vậy bạn không thể sử dụng điều đó cho các chuỗi có độ dài thay đổi.

Thay vào đó, hãy sử dụng seq 2 $maxphương thức như người dùng mob đã nêu .

Vì vậy, ví dụ của bạn sẽ là:

max=10
for i in `seq 2 $max`
do
    echo "$i"
done

Không có lý do chính đáng để sử dụng một lệnh bên ngoài như seqđể đếm và tăng số trong vòng lặp for, do đó bạn nên tránh sử dụng seq. Lệnh này được để lại để tương thích với bash cũ. Các lệnh tích hợp đủ nhanh. for (( EXP1; EXP2; EXP3 )) ...
cối xay

13
@miller for (( ... ))cú pháp không phải là POSIX và điều đó có nghĩa là nó sẽ không hoạt động ngoài những thứ như Alpine Linux. seqlàm.
Wernight

@Wernight Không chỉ là Linux Linux; #!/bin/shlà Dash trong Debian / Ubuntu.
Franklin Yu

72

Hãy thử phiên bản biểu thức số học của for:

max=10
for (( i=2; i <= $max; ++i ))
do
    echo "$i"
done

Điều này có sẵn trong hầu hết các phiên bản bash, và cũng phải tương thích với vỏ Bourne (sh).


1
@Flow: Hừm, tôi vừa thử nó trên một vài hệ thống (dựa trên Linux và BSD) với #! / Bin / sh và nó hoạt động tốt. Được gọi dưới bash và đặc biệt là dưới / bin / sh, vẫn hoạt động. Có lẽ phiên bản của vấn đề sh? Bạn có trên một số Unix cũ?
hệ thống PAUSE

8
Rất ít hệ thống có chuyên dụng sh, thay vào đó làm cho nó trở thành một liên kết với một vỏ khác. Lý tưởng nhất là một lớp vỏ được gọi như shvậy sẽ chỉ hỗ trợ các tính năng đó trong tiêu chuẩn POSIX, nhưng theo mặc định, hãy để một số tính năng bổ sung của chúng thông qua. Vòng lặp for kiểu C không phải là một tính năng POSIX, nhưng có thể ở shchế độ bởi lớp vỏ thực tế.
chepner

27

Bước vòng lặp thủ công:

i = 0
tối đa = 10
trong khi [$ i -lt $ max]
làm
    tiếng vang "đầu ra: $ i"
    đúng $ ((i ++))
làm xong

Nếu bạn không phải hoàn toàn POSIX, bạn có thể sử dụng số học cho vòng lặp:

tối đa = 10
cho ((i = 0; i <max; i ++)); làm tiếng vang "đầu ra: $ i"; làm xong

Hoặc sử dụng jot (1) trên các hệ thống BSD:

cho i bằng $ (ký 0 0); làm tiếng vang "đầu ra: $ i"; làm xong

3
true $(( i++ ))không hoạt động trong mọi trường hợp, vì vậy hầu hết di động sẽ được true $((i=i+1)).
Lưu lượng

bán đại tràng không nên vào "for ((i = 0; i <max; i ++));"
logan

9

Có nhiều hơn một cách để làm điều đó.

max=10
for i in `eval "echo {2..$max}"`
do
    echo "$i"
done

7
Một rủi ro bảo mật, vì evalsẽ đánh giá bất cứ điều gì bạn đặt maxra. Hãy xem xét max="2}; echo ha; #", sau đó thay thế echo habằng một cái gì đó phá hoại hơn.
chepner

6
(S) anh ta đặt tối đa là 10. Không có rủi ro.
Conrad Meyer

9

Nếu seqlệnh có sẵn trên hệ thống của bạn:

for i in `seq 2 $max`
do
  echo "output: $i"
done

Nếu không, sau đó sử dụng người nghèo seqvới perl:

seq=`perl -e "\$,=' ';print 2..$max"`
for i in $seq
do
  echo "output: $i"
done

Xem những dấu ngoặc kép.


Tôi chỉ kiểm tra xem; Dường như không phải vậy.
Eykanal

5

Đây là một cách:
Bash:

max=10
for i in $(bash -c "echo {2..${max}}"); do echo $i; done

Cách Bash ở trên cũng sẽ hoạt động kshzshkhi bash -cđược thay thế bằng ksh -choặc zsh -ctương ứng.

Lưu ý: for i in {2..${max}}; do echo $i; donehoạt động trong zshksh.


4

Chúng ta có thể lặp vòng lặp như lập trình C.

#!/bin/bash
for ((i=1; i<=20; i=i+1))
do 
      echo $i
done

2

Ở đây nó hoạt động trên Mac OS X.

Nó bao gồm ví dụ về ngày BSD, cách tăng và giảm ngày cũng:

for ((i=28; i>=6 ; i--));
do
    dat=`date -v-${i}d -j "+%Y%m%d"` 
    echo $dat
done

2

Chà, vì tôi chưa seqcài đặt lệnh trên hệ thống của mình (Mac OS X v10.6.1 (Snow Leopard)), nên cuối cùng tôi đã sử dụng một whilevòng lặp:

max=5
i=1

while [ $max -gt $i ]
do
    (stuff)
done

* Shrugs * Dù làm việc gì.


2
seq là tương đối mới. Tôi chỉ tìm hiểu về nó một vài tháng trước. Nhưng bạn có thể sử dụng vòng lặp 'for' !! Nhược điểm của 'while' là bạn phải nhớ tăng bộ đếm ở đâu đó bên trong vòng lặp, hoặc vòng lặp khác đi xuống.
hệ thống PAUSE

1

Tất cả đều làm {1..8}và nên tất cả là POSIX. Họ cũng sẽ không phá vỡ nếu bạn đặt một điều kiện continuetrong vòng lặp. Cách thức kinh điển:

f=
while [ $((f+=1)) -le 8 ]
do
  echo $f
done

Cách khác:

g=
while
  g=${g}1
  [ ${#g} -le 8 ]
do
  echo ${#g}
done

và khác:

set --
while
  set $* .
  [ ${#} -le 8 ]
do
  echo ${#}
done

1

Sử dụng:

max=10
for i in `eval echo {2..$max}`
do
    echo $i
done

Bạn cần lệnh gọi 'eval' rõ ràng để đánh giá lại {} sau khi thay thế biến.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.