Computer >> Máy Tính >  >> Lập trình >> Lập trình BASH

Cách viết vòng lặp trong Bash

Một lý do phổ biến mà mọi người muốn tìm hiểu Unix shell là để mở khóa sức mạnh của xử lý hàng loạt. Nếu bạn muốn thực hiện một số tập hợp hành động trên nhiều tệp, một trong những cách để thực hiện điều đó là xây dựng một lệnh lặp lại trên các tệp đó. Trong thuật ngữ lập trình, điều này được gọi là điều khiển thực thi, và một trong những ví dụ phổ biến nhất về nó là for vòng lặp.

Đ cho vòng lặp là một công thức mô tả chi tiết những hành động bạn muốn máy tính của mình thực hiện cho mỗi đối tượng dữ liệu (chẳng hạn như một tệp) mà bạn chỉ định.

Vòng lặp for cổ điển

Một vòng lặp dễ dàng để thử là một vòng lặp phân tích một tập hợp các tệp. Đây có thể không phải là một vòng lặp hữu ích, nhưng đó là một cách an toàn để chứng minh với bản thân rằng bạn có khả năng xử lý từng tệp trong một thư mục riêng lẻ. Đầu tiên, hãy tạo một môi trường thử nghiệm đơn giản bằng cách tạo một thư mục và đặt một số bản sao của một số tệp vào đó. Lúc đầu, bất kỳ tệp nào cũng có thể thực hiện được, nhưng các ví dụ sau này yêu cầu tệp đồ họa (chẳng hạn như JPEG, PNG hoặc tương tự). Bạn có thể tạo thư mục và sao chép tệp vào đó bằng trình quản lý tệp hoặc trong terminal:

 ví dụ $ mkdir 
$ cp ~ / Pictures / holiday / *. {png, jpg} ví dụ

Thay đổi thư mục thành thư mục mới của bạn, sau đó liệt kê các tệp trong đó để xác nhận rằng môi trường thử nghiệm của bạn là những gì bạn mong đợi:

 $ cd example 
$ ls -1
cat.jpg
design_maori.png
otago.jpg
Waterfall.png

Cú pháp để lặp qua từng tệp riêng lẻ trong một vòng lặp là:tạo một biến ( f cho tệp chẳng hạn). Sau đó, xác định tập dữ liệu mà bạn muốn biến xoay vòng qua. Trong trường hợp này, hãy duyệt qua tất cả các tệp trong thư mục hiện tại bằng cách sử dụng * ký tự đại diện ( * ký tự đại diện khớp với mọi thứ ). Sau đó, chấm dứt mệnh đề giới thiệu này bằng dấu chấm phẩy (; ).

 $ for f in * ; 

Tùy thuộc vào sở thích của mình, bạn có thể chọn nhấn Quay lại nơi đây. Trình bao sẽ không cố gắng thực hiện vòng lặp cho đến khi nó hoàn tất về mặt cú pháp.

Tiếp theo, xác định những gì bạn muốn xảy ra với mỗi lần lặp lại của vòng lặp. Để đơn giản, hãy sử dụng tệp lệnh để nhận một chút dữ liệu về mỗi tệp, được biểu thị bằng f biến (nhưng được thêm vào trước bằng $ để yêu cầu trình bao hoán đổi giá trị của biến cho bất kỳ giá trị nào mà biến hiện đang chứa):

 do file $f ; 

Kết thúc mệnh đề bằng một dấu chấm phẩy khác và đóng vòng lặp:

 done 

Nhấn Quay lại để bắt đầu chu trình vỏ thông qua mọi thứ trong thư mục hiện tại. for vòng lặp chỉ định từng tệp, từng tệp một, cho biến f và chạy lệnh của bạn:

 $ cho f in *; do 
> file $ f;
> done
cat.jpg:Dữ liệu hình ảnh JPEG, tiêu chuẩn EXIF ​​2.2
design_maori.png:Dữ liệu hình ảnh PNG, 4608 x 2592,8-bit / color RGB, không xen kẽ
otago.jpg:Dữ liệu hình ảnh JPEG, tiêu chuẩn EXIF ​​2.2
Waterfall.png:Dữ liệu hình ảnh PNG, 4608 x 2592, 8 bit / màu RGB, không xen kẽ

Bạn cũng có thể viết nó theo cách này:

 $ cho f in *; làm tập tin $ f; done 
cat.jpg:Dữ liệu hình ảnh JPEG, tiêu chuẩn EXIF ​​2.2
design_maori.png:Dữ liệu hình ảnh PNG, 4608 x 2592, 8-bit / màu RGB, không xen kẽ
otago.jpg:Dữ liệu hình ảnh JPEG, tiêu chuẩn EXIF ​​2.2
thác nước.png:Dữ liệu hình ảnh PNG, 4608 x 2592, RGB 8 bit / màu, không xen kẽ

Cả định dạng nhiều dòng và một dòng đều giống nhau đối với trình bao của bạn và tạo ra các kết quả giống hệt nhau.

Một ví dụ thực tế

Đây là một ví dụ thực tế về cách một vòng lặp có thể hữu ích cho việc tính toán hàng ngày. Giả sử bạn có một bộ sưu tập ảnh kỳ nghỉ muốn gửi cho bạn bè. Các tệp ảnh của bạn rất lớn, làm cho chúng quá lớn để gửi email và không thuận tiện khi tải lên dịch vụ chia sẻ ảnh của bạn. Bạn muốn tạo phiên bản web nhỏ hơn cho ảnh của mình, nhưng bạn có 100 ảnh và không muốn dành thời gian giảm từng ảnh, từng ảnh một.

Trước tiên, hãy cài đặt ImageMagick lệnh sử dụng trình quản lý gói của bạn trên Linux, BSD hoặc Mac. Ví dụ:trên Fedora và RHEL:

 $ sudo dnf install ImageMagick 

Trên Ubuntu hoặc Debian:

 $ sudo apt install ImageMagick 

Trên BSD, sử dụng cổng hoặc pkgsrc. Trên Mac, sử dụng Homebrew hoặc MacPorts.

Sau khi cài đặt ImageMagick, bạn có một tập hợp các lệnh mới để thao tác trên ảnh.

Tạo thư mục đích cho các tệp bạn sắp tạo:

 $ mkdir tmp 

Để giảm từng ảnh xuống còn 33% so với kích thước ban đầu, hãy thử vòng lặp này:

 $ for f in * ; do convert $f -scale 33% tmp/$f ; done 

Sau đó, xem trong tmp thư mục để xem ảnh được chia tỷ lệ của bạn.

Bạn có thể sử dụng bất kỳ số lượng lệnh nào trong vòng lặp, vì vậy nếu bạn cần thực hiện các hành động phức tạp trên một loạt tệp, bạn có thể đặt toàn bộ quy trình làm việc của mình giữa do xong tuyên bố của một for vòng. Ví dụ:giả sử bạn muốn sao chép từng ảnh đã xử lý thẳng vào thư mục ảnh được chia sẻ trên máy chủ lưu trữ web của mình và xóa tệp ảnh khỏi hệ thống cục bộ của bạn:

 $ cho f in *; thực hiện 
chuyển đổi $ f -scale 33% tmp / $ f
scp -i seth_web tmp / $ f seth@example.com:~ / public_html
rác tmp / $ f;
Xong

Đối với mỗi tệp được xử lý bởi for vòng lặp, máy tính của bạn tự động chạy ba lệnh. Điều này có nghĩa là nếu bạn xử lý chỉ 10 ảnh theo cách này, bạn sẽ lưu cho mình 30 lệnh và có thể ít nhất là nhiều phút.

Giới hạn vòng lặp của bạn

Một vòng lặp không phải lúc nào cũng phải xem xét mọi tệp. Bạn có thể chỉ muốn xử lý các tệp JPEG trong thư mục mẫu của mình:

 $ cho f in * .jpg; chuyển đổi $ f -scale 33% tmp / $ f; xong 
$ ls -m tmp
cat.jpg, otago.jpg

Hoặc, thay vì xử lý tệp, bạn có thể cần lặp lại một hành động một số lần cụ thể. Đ cho biến của vòng lặp được xác định bởi bất kỳ dữ liệu nào bạn cung cấp, vì vậy bạn có thể tạo một vòng lặp lặp qua các số thay vì tệp:

 $ cho n trong {0..4}; làm echo $ n; thực hiện xong 
0
1
2
3
4

Nhiều vòng lặp hơn

Bây giờ bạn đã biết đủ để tạo các vòng lặp của riêng mình. Cho đến khi bạn cảm thấy thoải mái với việc lặp lại, hãy sử dụng chúng trên bản sao của các tệp bạn muốn xử lý và thường xuyên nhất có thể, hãy sử dụng các lệnh có các biện pháp bảo vệ tích hợp để ngăn bạn chặn dữ liệu của mình và mắc phải những lỗi không thể sửa chữa, chẳng hạn như vô tình đổi tên toàn bộ thư mục tệp thành cùng một tên, mỗi tên ghi đè lên tên kia .

Đối với for nâng cao chủ đề vòng lặp, đọc tiếp.

Không phải tất cả các shell đều là Bash

for từ khóa được tích hợp trong Bash shell. Nhiều shell tương tự sử dụng cùng một từ khóa và cú pháp, nhưng một số shell, như tcsh, sử dụng một từ khóa khác, như foreach , thay vào đó.

Trong tcsh, cú pháp tương tự về tinh thần nhưng chặt chẽ hơn Bash. Trong mẫu mã sau, không nhập chuỗi foreach? ở dòng 2 và 3. Đây là lời nhắc phụ cảnh báo bạn rằng bạn vẫn đang trong quá trình xây dựng vòng lặp của mình.

 $ foreach f (*) 
foreach? tệp $ f
foreach? end
cat.jpg:Dữ liệu hình ảnh JPEG, tiêu chuẩn EXIF ​​2.2
design_maori.png:Dữ liệu hình ảnh PNG, 4608 x 2592, 8-bit / màu RGB, không xen kẽ
otago.jpg:Dữ liệu hình ảnh JPEG, tiêu chuẩn EXIF ​​2.2
thác nước.png:Dữ liệu hình ảnh PNG, 4608 x 2592, RGB 8 bit / màu, không xen kẽ

Trong tcsh, cả foreach kết thúc phải xuất hiện một mình trên các dòng riêng biệt, vì vậy bạn không thể tạo cho lặp lại trên một dòng như bạn có thể với Bash và các trình bao tương tự.

Đối với các vòng lặp với lệnh find

Về lý thuyết, bạn có thể tìm thấy một trình bao không cung cấp for chức năng vòng lặp, hoặc bạn có thể chỉ thích sử dụng một lệnh khác với các tính năng được bổ sung.

Tìm thấy lệnh là một cách khác để triển khai chức năng của for vòng lặp, vì nó cung cấp một số cách để xác định phạm vi của tệp nào sẽ bao gồm trong vòng lặp của bạn cũng như các tùy chọn để xử lý song song.

Tìm thấy lệnh này nhằm giúp bạn tìm các tệp trên ổ cứng của mình. Cú pháp của nó rất đơn giản:bạn cung cấp đường dẫn của vị trí bạn muốn tìm kiếm và tìm tìm tất cả các tệp và thư mục:

 $ tìm. 
.
./cat.jpg
./design_maori.png
./otago.jpg
./waterfall.png

Bạn có thể lọc kết quả tìm kiếm bằng cách thêm một số phần của tên:

 $ tìm. -name "* jpg" 
./cat.jpg
./otago.jpg

Điều tuyệt vời về find là mỗi tệp mà nó tìm thấy có thể được đưa vào một vòng lặp bằng cách sử dụng -exec lá cờ. Ví dụ:để chỉ thu nhỏ ảnh PNG trong thư mục mẫu của bạn:

 $ tìm. -name "* png" -exec convert {} -scale 33% tmp / {} \; 
$ ls -m tmp
design_maori.png, Waterfall.png

Trong -exec mệnh đề, các ký tự trong ngoặc {} đứng cho bất kỳ mục nào tìm thấy đang xử lý (nói cách khác, bất kỳ tệp nào kết thúc bằng PNG đã được định vị, mỗi lần một tệp). -exec mệnh đề phải được kết thúc bằng dấu chấm phẩy, nhưng Bash thường cố gắng sử dụng dấu chấm phẩy cho chính nó. Bạn "thoát" dấu chấm phẩy với dấu gạch chéo ngược ( \; ) để tìm biết coi dấu chấm phẩy đó là ký tự kết thúc.

Tìm thấy lệnh rất tốt trong những gì nó làm, và đôi khi nó có thể quá tốt. Ví dụ:nếu bạn sử dụng lại nó để tìm tệp PNG cho một quá trình ảnh khác, bạn sẽ gặp một số lỗi:

 $ tìm. -name "* png" -exec convert {} -flip -flop tmp / {} \; 
convert:không thể mở hình ảnh `tmp /./ tmp / design_maori.png ':
Không có tệp hoặc thư mục nào như vậy @ error / blob.c / OpenBlob / 2643.
...

Có vẻ như tìm thấy đã định vị tất cả các tệp PNG — không chỉ những tệp trong thư mục hiện tại của bạn (. ) mà còn cả những người bạn đã xử lý trước đó và đặt trong tmp của bạn thư mục con. Trong một số trường hợp, bạn có thể muốn tìm để tìm kiếm thư mục hiện tại cùng với tất cả các thư mục khác trong đó (và tất cả các thư mục trong những ). Nó có thể là một công cụ xử lý đệ quy mạnh mẽ, đặc biệt là trong các cấu trúc tệp phức tạp (như thư mục của nghệ sĩ âm nhạc chứa thư mục album chứa đầy tệp nhạc), nhưng bạn có thể hạn chế điều này bằng -maxdepth tùy chọn.

Để chỉ tìm các tệp PNG trong thư mục hiện tại (không bao gồm các thư mục con):

 $ find . -maxdepth 1 -name "*png" 

Để tìm và xử lý các tệp trong thư mục hiện tại cùng với một cấp độ bổ sung của các thư mục con, hãy tăng độ sâu tối đa lên 1:

 $ find . -maxdepth 2 -name "*png" 

Mặc định của nó là đi xuống tất cả các thư mục con.

Vòng lặp để mang lại niềm vui và lợi nhuận

Bạn càng sử dụng nhiều vòng lặp, bạn càng tiết kiệm được nhiều thời gian và công sức cũng như các nhiệm vụ bạn có thể giải quyết càng lớn. Bạn chỉ là một người dùng, nhưng với một vòng lặp được cân nhắc kỹ lưỡng, bạn có thể giúp máy tính của mình thực hiện công việc khó khăn.

Bạn có thể và nên coi việc lặp lại giống như bất kỳ lệnh nào khác, giữ nó luôn sẵn sàng khi bạn cần lặp lại một hoặc hai hành động trên một số tệp. Tuy nhiên, nó cũng là một cửa ngõ hợp pháp để lập trình nghiêm túc, vì vậy nếu bạn phải hoàn thành một nhiệm vụ phức tạp trên bất kỳ số lượng tệp nào, hãy dành một chút thời gian trong ngày để lập kế hoạch cho quy trình làm việc của bạn. Nếu bạn có thể đạt được mục tiêu của mình trên một tệp, thì hãy gói quá trình có thể lặp lại đó trong cho vòng lặp tương đối đơn giản và "lập trình" duy nhất được yêu cầu là hiểu cách thức hoạt động của các biến và đủ tổ chức để tách các tệp chưa xử lý khỏi các tệp đã xử lý. Với một chút thực hành, bạn có thể chuyển từ người dùng Linux sang người dùng Linux biết cách viết vòng lặp, vì vậy hãy ra khỏi đó và làm cho máy tính của bạn hoạt động cho phù hợp với bạn!