Có cách nào để đọc các dòng từ đầu ra lệnh?


8

Tôi có một lệnh xử lý trước để xuất một tập tin

./preprocess.sh > preprocessed_file 

preprocessed_filesẽ được sử dụng như thế này

while read line
do

    ./research.sh $line &

done < preprocessed_file 

rm -f preprocessed_file

Có cách nào để hướng đầu ra đến while read linephần thay vì xuất ra tiền xử lý_file không? Tôi nghĩ nên có một cách tốt hơn ngoài việc sử dụng temp này preprocessed_file.

Câu trả lời:


8

Bạn có thể sử dụng thay thế quá trình bash :

while IFS= read -r line; do
  ./research.sh "$line" &
done < <(./preprocess.sh)

Một số ưu điểm của quá trình thay thế:

  • Không cần lưu tập tin tạm thời.
  • Hiệu suất tốt hơn. Đọc từ một quá trình khác thường nhanh hơn ghi vào đĩa, sau đó đọc lại.
  • Tiết kiệm thời gian để tính toán kể từ khi nó được thực hiện đồng thời với mở rộng tham số và biến, thay thế lệnh và mở rộng số học

mũi tên trái đôi (<<) nghĩa là gì?
Marcus Thornton

@MarcusThornton: <là một chuyển hướng, trong khi <(...)là cú pháp thay thế quá trình. Bạn nên đọc: gnu.org/software/bash/manual/html_node/ khuyên để biết thêm chi tiết.
cuonglm

Hiểu rồi. <(...)là một phần của cú pháp.
Marcus Thornton

2
Nó không nhất thiết phải nhanh hơn. Bởi vì khi đọc từ một ống readphải đọc từng byte một lần, trong khi nó có thể tối ưu hóa mọi thứ bằng cách đọc các đoạn lớn hơn và tìm cách lùi lại khi đọc từ một tệp thông thường. Tốt nhất là tránh while readcác vòng lặp hoàn toàn ở nơi đầu tiên khi có thể. Cũng lưu ý rằng bạn cần IFS= read -r linephải đọc dòng vào $line. Và bỏ không $lineđược trích dẫn (gọi toán tử split + global) ở đây có lẽ không có ý nghĩa gì.
Stéphane Chazelas

1
@mikeerv, các lệnh thường là bộ đệm dòng ( trái ngược với bộ đệm đầy đủ) đầu ra của chúng khi nó đi đến một thiết bị đầu cuối. Ở đây tôi đang nói rằng readshell dựng sẵn đọc một ký tự tại một thời điểm khi đọc từ một đường ống (bất kể những gì ở đầu kia của ống readkhông có cách nào để biết), đó là một trong những lý do while readvòng lặp rất chậm.
Stéphane Chazelas

15

Đúng! Bạn có thể sử dụng một đường ống quy trình |.

./preprocess.sh |
    while IFS= read -r line
    do
        ./research.sh "$line" &
    done

Một ống quy trình chuyển đầu ra tiêu chuẩn ( stdout) của một quy trình sang đầu vào tiêu chuẩn ( stdin) của quy trình tiếp theo.

Bạn có thể tùy ý đặt một ký tự dòng mới theo a |và mở rộng lệnh sang dòng tiếp theo.

Lưu ý: a|btương đương với b < <(a), nhưng không có các tệp ma thuật và theo thứ tự dễ đọc hơn, đặc biệt là khi đường ống dài hơn.

a|b|c tương đương với c < <(b < <(a))

a|b|c|d|ee < < (d < <(c < <(b < <(a))))


3
Lưu ý: Giải pháp này với đường ống có ưu điểm là dễ di chuyển hơn thay thế quá trình (không được hỗ trợ bởi một số vỏ POSIX như dấu gạch ngang). Vẫn liên quan đến tính di động, phía bên phải của một đường ống có thể được thực thi trong một lớp con (điều này phụ thuộc vào lớp vỏ), do đó, bất kỳ tác dụng phụ nào (như các biến cài đặt) có thể không ảnh hưởng đến môi trường của tập lệnh shell.
vinc17

Nói chung sẽ an toàn hơn khi đặt các tham chiếu biến như $linevào dấu ngoặc kép (ví dụ: trong tập lệnh của bạn ./research.sh "$line" &).
G-Man nói 'Phục hồi Monica'

1
@ G-Man Có thể không trong bối cảnh này. Nếu research.shhoạt động với mảng đối số dòng lệnh và $line, ví dụ: "một hai", với ý định rằng đối số thứ nhất là "một" và đối số thứ hai là "hai", trích dẫn $linesẽ làm cho điều đó không thể - thay vào đó, đối số thứ nhất sẽ là "một hai" và sẽ không có cái thứ hai ...
goldilocks

2
" a|btương đương vớib < <(a) " - gần, nhưng không hoàn toàn. Trong phiên bản ống, cả hai bên của ống được chạy trong các lớp con, trong khi ở phiên bản thay thế quy trình, chỉ có quy trình được thay thế được chạy trong một lớp con, nhưng ađược chạy trong phạm vi của mức vỏ hiện đang thực thi. Điều này có ý nghĩa quan trọng đối với phạm vi của các biến được đặt tronga
Chấn thương kỹ thuật số
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.