2015-12-17 22 views
12

Sử dụng thay thế tiến trình bash, tôi muốn chạy đồng thời hai lệnh khác nhau trên một tệp. Trong ví dụ này không cần thiết nhưng hãy tưởng tượng rằng "cat/usr/share/dict/words" là một hoạt động rất tốn kém chẳng hạn như giải nén tệp 50gb.Kết quả không chính xác với sự thay thế và đuôi của quá trình bash?

cat /usr/share/dict/words | tee >(head -1 > h.txt) >(tail -1 > t.txt) > /dev/null 

Sau lệnh này, tôi muốn h.txt chứa dòng đầu tiên của tệp từ "A" và t.txt chứa dòng cuối cùng của tệp "Zyzzogeton".

Tuy nhiên điều thực sự xảy ra là h.txt chứa "A" nhưng t.txt chứa "argillaceo", khoảng 5% vào tệp.

Tại sao điều này lại xảy ra? Có vẻ như quá trình "đuôi" đang kết thúc sớm hoặc các luồng đang bị lẫn lộn.

Chạy một lệnh tương tự như thế này cư xử như mong đợi:

cat /usr/share/dict/words | tee >(grep ^a > a.txt) >(grep ^z > z.txt) > /dev/null 

Sau lệnh này tôi mong đợi a.txt để chứa tất cả các từ bắt đầu bằng "a", trong khi z.txt chứa tất cả các các từ bắt đầu bằng "z", chính xác là những gì đã xảy ra.

Vậy tại sao tính năng này không hoạt động với "đuôi" và các lệnh khác sẽ không hoạt động như thế nào?

+1

Tôi nghĩ rằng đây có liên quan đến http://stackoverflow.com/questions/4489139/bash-process-replace-and-syncing cho thấy rằng các tiến trình có trong lối ra thay thế ngay sau khi lệnh bên ngoài kết thúc, nhưng thẳng thắn tôi không thể chứng minh đó là vấn đề hiện tại với bất kỳ lệnh nào tôi đã cố gắng cho đến nay –

Trả lời

10

Ok, những gì có thể xảy ra là một khi lệnh head -1 kết thúc nó thoát và gây tee để có được một SIGPIPE nó cố gắng ghi vào ống tên rằng thiết lập thay thế tiến trình đó tạo ra một EPIPE và theo man 2 write cũng sẽ tạo ra SIGPIPE trong quá trình viết, gây ra tee để thoát và buộc phải tail -1 thoát ngay lập tức và cat ở bên trái cũng nhận được SIGPIPE.

Chúng ta có thể thấy điều này tốt hơn một chút nếu chúng ta bổ sung thêm một chút để quá trình với head và làm cho sản lượng cả hai dễ dự đoán hơn và cũng có thể ghi vào stderr mà không dựa vào các tee:

for i in {1..30}; do echo "$i"; echo "$i" >&2; sleep 1; done | tee >(head -1 > h.txt; echo "Head done") >(tail -1 > t.txt) >/dev/null 

mà khi tôi chạy nó đã cho tôi kết quả:

1 
Head done 
2 

nên nó có chỉ 1 lần lặp nhiều vòng trước khi tất cả mọi thứ đã thoát (mặc dù t.txt vẫn chỉ có 1 trong đó). Nếu sau đó chúng tôi đã làm

echo "${PIPESTATUS[@]}" 

chúng ta thấy

141 141 

this question quan hệ với SIGPIPE trong một thời trang rất giống với những gì chúng ta đang thấy ở đây.

Nhân viên bảo trì lõi đã thêm điều này làm ví dụ cho tee "gotchas" của họ cho hậu thế tương lai.

Đối với một cuộc thảo luận với các nhà phát triển về cách thức này phù hợp với POSIX tuân thủ, bạn có thể xem báo cáo (notabug khép kín) tại http://debbugs.gnu.org/cgi/bugreport.cgi?bug=22195

Nếu bạn có quyền truy cập vào GNU phiên bản 8.24 họ đã thêm một số tùy chọn (không phải trong POSIX) có thể giúp như -p hoặc --output-error=warn. Nếu không, bạn có thể mất một chút của một nguy cơ nhưng có được chức năng mong muốn trong câu hỏi bằng cách bẫy và bỏ qua SIGPIPE:

trap '' PIPE 
for i in {1..30}; do echo "$i"; echo "$i" >&2; sleep 1; done | tee >(head -1 > h.txt; echo "Head done") >(tail -1 > t.txt) >/dev/null 
trap - PIPE 

sẽ có kết quả mong đợi ở cả h.txtt.txt, nhưng nếu cái gì khác xảy ra mà SIGPIPE truy nã để được xử lý một cách chính xác, bạn sẽ không may mắn với cách tiếp cận này.

Một tùy chọn khác hacky sẽ được số không ra t.txt trước khi bắt đầu sau đó không để cho các head quá trình danh sách kết thúc cho đến khi nó không phải là zero chiều dài:

> t.txt; for i in {1..10}; do echo "$i"; echo "$i" >&2; sleep 1; done | tee >(head -1 > h.txt; echo "Head done"; while [ ! -s t.txt ]; do sleep 1; done) >(tail -1 > t.txt; date) >/dev/null 
+1

Hành vi được chỉ định POSIX cho 'tee' là để nó tiếp tục hoạt động ngay cả khi một trong những độc giả của nó thoát - vì vậy nếu bạn thấy điều gì đó trái ngược, đó thực sự là lỗi. –

+0

"Nếu ghi vào bất kỳ toán hạng tệp được mở thành công nào, ghi vào các toán hạng tệp đã mở thành công và đầu ra tiêu chuẩn sẽ tiếp tục, nhưng trạng thái thoát sẽ khác không. Nếu không, các hành động mặc định được chỉ định trong Mô tả Tiện ích Mặc định sẽ áp dụng." - http://pubs.opengroup.org/onlinepubs/9699919799/utilities/tee.html –

+0

@CharlesCũng tốt các kết quả ở trên dành cho phiên bản cũ hơn tôi đoán là 8,5, tôi có thể thử lại. Ngoài ra, tôi chưa từng nghiên cứu sâu đủ để biết liệu quá trình thay thế có hiển thị như là một tập tin đóng hay không thực sự tăng SIGPIPE khi quá trình đó kết thúc, tôi có nhiều việc phải làm trước khi gửi báo cáo lỗi Tôi đoán –

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