Làm cách nào để viết vòng lặp for trong bash


Câu trả lời:


103

Từ trang web này :

for i in $(seq 1 10);
do
    echo $i
done

10
Điều đáng nói là phạm vi được chỉ định ở đây là bao gồm . Theo đó, tôi có nghĩa là bạn sẽ thấy toàn bộ phạm vi (1 đến 10) được in vào bảng điều khiển.
Jamie

62
for ((i = 0 ; i < max ; i++ )); do echo "$i"; done

nếu chúng ta có một biến như ArrayLength=${#array[@]}thế nào để chúng ta sử dụng nó ở đây thay vì max?
Kasun Siyambalapitiya

34

Bash forbao gồm một biến (trình lặp) và danh sách các từ mà trình lặp sẽ lặp lại.

Vì vậy, nếu bạn có một danh sách các từ hạn chế, chỉ cần đặt chúng theo cú pháp sau:

for w in word1 word2 word3
do
  doSomething($w)
done

Có thể bạn muốn lặp lại một số số, vì vậy bạn có thể sử dụng seqlệnh để tạo danh sách các số cho mình: (từ 1 đến 100 chẳng hạn)

seq 1 100

và sử dụng nó trong vòng lặp FOR:

for n in $(seq 1 100)
do
  doSomething($n)
done

Lưu ý $(...)cú pháp. Đó là một hành vi bash, nó cho phép bạn vượt qua các đầu ra từ một lệnh (trong trường hợp của chúng tôi từ seq) khác (các for)

Điều này thực sự hữu ích khi bạn phải lặp lại tất cả các thư mục trong một số đường dẫn, ví dụ:

for d in $(find $somepath -type d)
do
  doSomething($d)
done

Khả năng tạo danh sách là vô hạn.


2
Câu trả lời tốt, nhưng bạn có thể muốn bao gồm for ((i = 0; i <MAX; i ++)); làm doSomething ($ i); biến thể được thực hiện là tốt. Tôi nghĩ rằng điều này thường được ưu tiên cho biến thể for i trong $ (seq 0 MAX) vì biến thể sau sẽ tạo ra tất cả các số từ 0 đến MAX trước khi thực sự thực hiện vòng lặp.
mweerden

30

Bash 3.0+ có thể sử dụng cú pháp này:

for i in {1..10} ; do ... ; done

.. mà tránh tạo ra một chương trình bên ngoài để mở rộng chuỗi (chẳng hạn như seq 1 10).

Tất nhiên, điều này có cùng một vấn đề với for(())giải pháp, bị ràng buộc với bash và thậm chí là một phiên bản cụ thể (nếu điều này quan trọng với bạn).


14

Hãy thử bashtrợ giúp tích hợp:


$ help for

for: for NAME [in WORDS ... ;] do COMMANDS; done
    The `for' loop executes a sequence of commands for each member in a
    list of items.  If `in WORDS ...;' is not present, then `in "$@"' is
    assumed.  For each element in WORDS, NAME is set to that element, and
    the COMMANDS are executed.
for ((: for (( exp1; exp2; exp3 )); do COMMANDS; done
    Equivalent to
        (( EXP1 ))
        while (( EXP2 )); do
            COMMANDS
            (( EXP3 ))
        done
    EXP1, EXP2, and EXP3 are arithmetic expressions.  If any expression is
    omitted, it behaves as if it evaluates to 1.


5
#! /bin/bash

function do_something {
   echo value=${1}
}

MAX=4
for (( i=0; i<MAX; i++ )) ; {
   do_something ${i}
}

Dưới đây là một ví dụ cũng có thể hoạt động trong các trình bao cũ hơn, trong khi vẫn hiệu quả với số lượng lớn:

Z=$(date) awk 'BEGIN { for ( i=0; i<4; i++ ) { print i,"hello",ENVIRON["Z"]; } }'

Nhưng chúc may mắn khi làm được những điều hữu ích bên trong awk: Làm cách nào để sử dụng các biến shell trong tập lệnh awk?


2
Tôi đã không nhận thấy nó trước đây, nhưng một cú pháp tương tự được hiển thị trong một trong những câu trả lời trước đó. Điều độc đáo ở đây là việc sử dụng dấu ngoặc nhọn thay vì cặp do/ điển hình done.
Brent Bradburn

4

Tôi thường thích sử dụng một biến thể nhỏ trên tiêu chuẩn cho vòng lặp. Tôi thường sử dụng điều này để chạy một lệnh trên một loạt các máy chủ từ xa. Tôi tận dụng khả năng mở rộng dấu ngoặc nhọn của bash để tạo các vòng lặp for cho phép tôi tạo các vòng lặp for không phải số.

Thí dụ:

Tôi muốn chạy lệnh thời gian hoạt động trên máy chủ giao diện người dùng 1-5 và máy chủ phụ trợ 1-3:

% for host in {frontend{1..5},backend{1..3}}.mycompany.com
    do ssh $host "echo -n $host; uptime"
  done

Tôi thường chạy lệnh này dưới dạng lệnh một dòng với dấu chấm phẩy ở cuối các dòng thay vì phiên bản dễ đọc hơn ở trên. Cân nhắc sử dụng chính là dấu ngoặc nhọn cho phép bạn chỉ định nhiều giá trị được chèn vào một chuỗi (ví dụ: kết quả đăng trước {foo, bar} trong prefoopost, prebarpost) và cho phép đếm / chuỗi bằng cách sử dụng dấu chấm kép (bạn có thể sử dụng a. .z, v.v.). Tuy nhiên, cú pháp dấu chấm kép là một tính năng mới của bash 3.0; các phiên bản trước sẽ không hỗ trợ điều này.


Liên quan đến điều này, điều gì sẽ xảy ra nếu $ host var là một dòng trống do một sự cố tình cờ nào đó? Nó vẫn sẽ bắn ssh. Vì vậy, làm thế nào để tôi tránh điều đó? Trong trường hợp của tôi, tôi đang làm điều gì đó khác và vì vậy câu trả lời của bạn sẽ giúp tôi. Tôi đang cố gắng kiểm tra Gmail để tìm các thư mới và nếu được tìm thấy, hãy gửi SMS về từ và chủ đề. Câu hỏi của tôi có nhãn "Kết nối hai lệnh Bash" nếu bạn muốn đọc nó.
Volomike

Tôi không tin là bạn sẽ nhận được $ host var trống. Điều này là do ví dụ trên đang sử dụng mở rộng dấu ngoặc nhọn. Vòng lặp for đặt biến $ host thành các giá trị: frontend1.mycompany.com frontend2.mycompany.com một cách rõ ràng. . backend1.mycompany.com Nhưng nếu bạn thấy một cách để nó có giá trị null; Tôi muốn biết. Bạn có thể thực thi ssh bên trong một bài kiểm tra có điều kiện nếu nó là một mối quan tâm.
terson

1

nếu bạn chỉ quan tâm đến giải pháp "for ((...))" được trình bày ở trên là tốt nhất, nhưng nếu bạn muốn thứ gì đó tuân thủ POSIX SH sẽ hoạt động trên tất cả các liên kết, bạn sẽ phải sử dụng "expr" và "while" và đó là bởi vì "(())" hoặc "seq" hoặc "i = i + 1" không di động giữa các shell khác nhau


0

Tôi luôn sử dụng các biến thể này để xử lý tệp ...

cho các tệp trong * .log; làm echo "Thực hiện công việc với: $ files"; echo "Làm nhiều thứ hơn với: $ files"; làm xong;

Nếu việc xử lý danh sách tệp là điều bạn quan tâm, hãy xem xét tùy chọn -execdir cho tệp .


Tôi nghĩ ý bạn là tùy chọn -execdir để tìm
Tạm dừng cho đến khi có thông báo mới.
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.