Khi nào nên sử dụng () so với {} trong bash?


74

Tôi đang nghiên cứu kịch bản shell với bash và tôi cần biết sự khác biệt giữa (...){...}. Làm thế nào để chọn một trong hai khi viết một kịch bản?



3
Bạn có nghĩa là trong bối cảnh chỉ nhóm nhóm?
heemayl

Câu trả lời:


87

Nếu bạn muốn các tác dụng phụ của danh sách lệnh ảnh hưởng đến trình bao hiện tại của bạn , hãy sử dụng {...}
Nếu bạn muốn loại bỏ bất kỳ tác dụng phụ nào, hãy sử dụng(...)

Ví dụ: tôi có thể sử dụng một subshell nếu tôi:

  • muốn thay đổi $IFSmột vài lệnh, nhưng tôi không muốn thay đổi $IFStoàn cầu cho trình bao hiện tại
  • cdở đâu đó, nhưng tôi không muốn thay đổi $PWDvỏ hiện tại

Đáng lưu ý rằng dấu ngoặc đơn có thể được sử dụng trong định nghĩa hàm:

  • sử dụng bình thường: niềng răng: cơ thể chức năng thực thi trong shell hiện tại; tác dụng phụ vẫn còn sau khi chức năng hoàn thành

    $ count_tmp() { cd /tmp; files=(*); echo "${#files[@]}"; }
    $ pwd; count_tmp; pwd
    /home/jackman
    11
    /tmp
    $ echo "${#files[@]}"
    11    
  • sử dụng bất thường: dấu ngoặc đơn: cơ thể chức năng thực thi trong một lớp con; tác dụng phụ biến mất khi thoát khỏi subshell

    $ cd ; unset files
    $ count_tmp() (cd /tmp; files=(*); echo "${#files[@]}")
    $ pwd; count_tmp; pwd
    /home/jackman
    11
    /home/jackman
    $ echo "${#files[@]}"
    0

Tài liệu


11
Sau nhiều năm phát triển hệ vỏ, tôi không biết bạn có thể sử dụng dấu ngoặc đơn để chạy các hàm trong các lớp con. Thật là một ý tưởng tuyệt vời để tránh gây ô nhiễm không gian tên toàn cầu!
l0b0

7
Sử dụng localtừ khóa đi một chặng đường dài để làm sạch ô nhiễm đó.
glenn jackman

2
Vâng, nhưng bạn phải nhớ khai báo mọi biến cục bộ, và nó làm tắc mã.
l0b0

4
Gợi ý: Nếu bạn muốn các hàm không có hiệu ứng phụ nhưng tránh cú pháp khai báo hàm bất thường (trình soạn thảo mã có thể không nhận biết được) thì chỉ cần sử dụng dấu ngoặc đơn trong lệnh gọi hàm thay vì khai báo:pwd; (count_tmp); pwd;
Juve

2
với vỏ ... foo () (:;) tương đương với foo () {(:;); } Đó là cách nó báo cáo nếu bạn yêu cầu!
anthony

23

Từ tài liệu bash chính thức :

()

( list )

Việc đặt một danh sách các lệnh giữa các dấu ngoặc đơn sẽ tạo ra một môi trường lớp con và mỗi lệnh trong danh sách sẽ được thực thi trong lớp con đó. Vì danh sách được thực thi trong một lớp con, các phép gán biến không còn hiệu lực sau khi lớp con hoàn thành.

{}

{ list; }

Đặt một danh sách các lệnh giữa các dấu ngoặc nhọn làm cho danh sách được thực thi trong bối cảnh shell hiện tại. Không có subshell được tạo ra. Danh sách dấu chấm phẩy (hoặc dòng mới) là bắt buộc.


9

Mã trong '{}' được thực thi trong luồng / tiến trình / môi trường hiện tại và các thay đổi được giữ nguyên, để đặt nó ngắn gọn hơn, mã được chạy trong phạm vi hiện tại.
Mã trong '()' được chạy bên trong một quy trình bash con riêng biệt bị loại bỏ sau khi thực thi. Quá trình con này thường được gọi là một vỏ con và có thể được coi là một phạm vi mới, giống như trẻ em.

Như một ví dụ, hãy xem xét ...

 ~ # { test_var=test }
 ~ # echo $test_var
 test
 ~ # ( test_var2=test2 )
 ~ # echo $test_var2

 ~ # 

Lưu ý trong ví dụ đầu tiên với '{}', biến vẫn được đặt ngay cả sau khi đóng '}', trong khi trong ví dụ với '()', biến không được đặt ngoài phạm vi của '()'.


4

(...)được sử dụng để chạy mã trong shell phụ. Mã được sử dụng {...}sẽ không được sử dụng trong lớp vỏ phụ.

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.