2010-03-14 41 views
17

Khi vòng lặp đệ quy qua các thư mục với các file có chứa không gian kịch bản shell tôi sử dụng là của mẫu đơn này, sao chép từ internet:"<<(cmd args)" có nghĩa là gì trong vỏ?

while IFS= read -r -d $'\0' file; do 
     dosomethingwith "$file"  # do something with each file 
    done < <(find /bar -name *foo* -print0) 

Tôi nghĩ rằng tôi hiểu được chút IFS, nhưng tôi không hiểu những gì ' < <(...) 'các ký tự có nghĩa là. Rõ ràng có một số loại đường ống đang diễn ra ở đây.

Rất khó để Google "< <", bạn thấy.

+0

Bạn không có nghĩa là "<<"? – reinierpost

+0

"man sh" là bạn của bạn, trong mọi trường hợp. – reinierpost

+4

Nó không phải là '<<' nhưng nó là '<' và '<(...) 'toán tử, nếu tôi nhớ đúng –

Trả lời

23

<() được gọi là process substitution trong hướng dẫn và tương tự như một đường ống nhưng chuyển đối số của biểu mẫu /dev/fd/63 thay vì sử dụng stdin.

< đọc đầu vào từ tệp có tên trên dòng lệnh.

Cùng, hai nhà khai thác những chức năng giống hệt như một đường ống, vì vậy nó có thể được viết lại như

find /bar -name *foo* -print0 | while read line; do 
    ... 
done 
+8

không giống nhau nếu bạn không được bắt đầu một vỏ bọc – knittl

+6

+1 vì bạn có tên chính xác cho ký hiệu. Như @knittl chỉ ra, nó không hoàn toàn giống với viết lại của bạn bởi vì vòng lặp sẽ chạy trong một hệ vỏ con, và bất kỳ thay đổi nào được thực hiện trong các biến bởi vòng lặp chỉ ảnh hưởng đến sub-shell, chứ không phải kịch bản chính. Bạn có thể đối phó với điều đó bằng cách chuyển hướng đầu ra của 'find' vào ''{while ...; làm ...; làm xong; ... phần còn lại của kịch bản ...; } '', sử dụng các dấu ngoặc để nhóm toàn bộ phần còn lại của tập lệnh - vòng lặp và các tài liệu khác - thành một phần con. –

+1

cảm ơn vì điều đó. Tôi có thể cảm thấy hộp sọ của tôi mở rộng trên một phần của bộ não mà làm kịch bản vỏ. Có một thuật ngữ chính xác để google làm cho nó dễ dàng hơn nhiều. Bây giờ tôi sẽ đi tìm hiểu những gì một subshell là. – stib

-3

Toán tử << giới thiệu một here-document, sẽ lấy đầu ra của lệnh khác làm đầu vào cho lệnh đầu tiên.

Cập nhật

Được rồi, vì vậy họ phải có thêm một vài điều cần vỏ kể từ khi tôi cuối cùng sử dụng nó 15 năm trước đây.
Vui lòng bỏ qua.

4

< chuyển hướng đến tiêu chuẩn.

<() có vẻ là một số loại ống ngược lại, như đã đề cập trên trang:

find /bar -name *foo* -print0 | \ 
while IFS= read -r -d $'\0' file; do 
    dosomethingwith "$file"  # do something with each file 
done 

sẽ không làm việc, bởi vì vòng lặp while sẽ được thực hiện trong một subshell, và bạn sẽ mất thay đổi được thực trong vòng lặp

+0

Câu trả lời này sẽ được hưởng lợi từ x-ref để 'xử lý thay thế' và một URL như http://www.gnu.org/software/bash/manual/bashref.html#Process-Substitution giải thích nó. Điểm mấu chốt là sub-shell và các thay đổi được thực hiện cho các biến trong sub-shell. Cách khác để đối phó với nó là: 'tìm ... | { trong khi ...; làm ...; làm xong; ... phần còn lại của kịch bản ...; } ', sử dụng các dấu ngoặc để chạy tất cả các phần còn lại của tập lệnh trong một hệ vỏ con thay vì chỉ vòng lặp while. –

3

< (lệnh) là quá trình thay thế. Về cơ bản, nó tạo ra một loại đặc biệt của tập tin được gọi là một "tên ống", sau đó chuyển hướng đầu ra của lệnh để được đặt tên theo đường ống. Vì vậy, ví dụ, giả sử bạn muốn trang thông qua một danh sách các tập tin trong một thư mục cực lớn. Bạn có thể làm điều này:

ls /usr/bin | more 

Hoặc này:

more <(ls /usr/bin) 

Nhưng KHÔNG này:

more $(ls /usr/bin) 

Lý do cho điều này trở nên rõ ràng khi bạn điều tra thêm:

~$ echo $(ls /tmp) 
gedit.maxtothemax.436748151 keyring-e0fuHW mintUpdate orbit-gdm orbit-maxtothemax plugtmp pulse-DE9F3Ei96ibD pulse-PKdhtXMmr18n ssh-wKHyBU1713 virtual-maxtothemax.yeF3Jo 
~$ echo <(ls /tmp) 
/dev/fd/63 
~$ cat <(ls /tmp) 
gedit.maxtothemax.436748151 
keyring-e0fuHW 
mintUpdate 
orbit-gdm 
orbit-maxtothemax 
plugtmp 
pulse-DE9F3Ei96ibD 
pulse-PKdhtXMmr18n 
ssh-wKHyBU1713 
virtual-maxtothemax.yeF3Jo 

/dev/fd/bất kỳ hành vi nào giống như tệp văn bản đầu ra của lệnh giữa dấu ngoặc đơn.

Các vấn đề liên quan