Làm thế nào tôi có thể sửa một lỗi ống hỏng?


36

Gần đây tôi đã cài đặt lại RVM (theo hướng dẫn tại http://rvm.io ) sau khi cài đặt Ubuntu 12.10 mới khi tôi có ổ SSD.

Bây giờ, khi tôi gõ: type rvm | head -1

Tôi nhận được lỗi sau:

rvm is a function
-bash: type: write error: Broken pipe

Nhưng nếu tôi lập tức lặp lại lệnh thì tôi chỉ nhận được:

rvm is a function

Và nó xuất hiện mọi thứ là ok? Chuyện gì đang xảy ra vậy? Tôi có thể làm gì để khắc phục nó? Nó không xảy ra luôn. Nó xuất hiện để lẻ tẻ hơn. Tôi đã cố gắng tìm một số kiểu mẫu cho nó nhưng chưa được.

Câu trả lời:


57

Thấy "vỡ ống" trong tình huống này là hiếm, nhưng bình thường.

Khi bạn chạy type rvm | head -1, bash thực thi type rvmtrong một quy trình, head -1trong một quy trình khác. 1 Thiết bị xuất chuẩn typeđược kết nối với đầu "ghi" của ống , stdin của headđầu "đọc". Cả hai quá trình chạy cùng một lúc.

Các head -1quá trình đọc dữ liệu từ thiết bị nhập chuẩn (thường là trong khối 8 kB), in ra một dòng đơn (theo -1lựa chọn), và lối thoát hiểm, gây ra "đọc" cuối đường ống để được đóng lại. Vì rvmhàm này khá dài (khoảng 11 kB sau khi được phân tích cú pháp và được xây dựng lại bằng bash), điều này có nghĩa là headthoát ra trong khi typevẫn còn một vài kB dữ liệu để ghi ra.

Tại thời điểm này, vì typeđang cố ghi vào một đường ống mà đầu kia đã bị đóng - một đường ống bị hỏng - hàm write () mà nó đã điều chỉnh sẽ trả về lỗi EPIPE, được dịch là "Đường ống bị hỏng". Ngoài lỗi này, kernel cũng gửi tín hiệu SIGPIPE tới type, theo mặc định sẽ giết quá trình ngay lập tức.

(Tín hiệu này rất hữu ích trong các vỏ tương tác, vì hầu hết người dùng không muốn quá trình đầu tiên tiếp tục chạy và cố gắng ghi vào nơi nào. Trong khi đó, các dịch vụ không tương tác bỏ qua SIGPIPE - sẽ không tốt cho daemon chạy dài chết vì một lỗi đơn giản như vậy - vì vậy họ thấy mã lỗi rất hữu ích.)

Tuy nhiên, việc truyền tín hiệu không phải là 100% ngay lập tức và có thể có trường hợp write () trả về EPIPE và quá trình tiếp tục chạy trong một thời gian ngắn trước khi nhận được tín hiệu. Trong trường hợp này, typecó đủ thời gian để thông báo ghi thất bại, dịch mã lỗi và thậm chí in thông báo lỗi sang thiết bị lỗi trước khi bị SIGPIPE giết. (Thông báo lỗi cho biết "-bash: type:" vì đây typelà lệnh tích hợp sẵn của bash.)

Điều này dường như phổ biến hơn trên các hệ thống nhiều CPU, vì typequy trình và mã phân phối tín hiệu của kernel có thể chạy trên các lõi khác nhau, theo nghĩa đen cùng một lúc.

Có thể xóa thông báo này bằng cách vá typenội dung (trong mã nguồn của bash) để thoát ngay lập tức khi nhận được EPIPE từ hàm write ().

Tuy nhiên, không có gì phải lo lắng và nó không liên quan đến rvmcài đặt của bạn dưới bất kỳ hình thức nào.


Cảm ơn bạn! Tôi đã lo lắng về nó. Tôi đã làm việc trong một giờ đáng để loay hoay đêm qua, khắc phục sự cố cài đặt rvm của tôi và sửa chữa nó để cố gắng sửa nó. Tôi vừa trao đổi với một ổ SSD và sử dụng LVM và mã hóa ổ cứng để có rất nhiều biến số được sử dụng và tôi không chắc chắn những gì có thể đã đi ngang. Cảm ơn bạn đã đưa tâm trí của tôi thoải mái!
Jason Shultz

Tôi đã được đường ống đầu ra của lsthông qua head -1trong nhiều năm qua, và hôm nay tôi nhận được một thông đường ống bị hỏng.
Tulains Córdova

1
(Lưu ý: Lỗi "Đường ống bị hỏng" không xuất phát từ tín hiệu. Nó xuất phát từ lỗi . Mặc dù vỏ có thể hiển thị các tin nhắn văn bản cho các lối thoát do tín hiệu, nhưng nó thường đủ thông minh để giả vờ rằng lối ra SIGPIPE là 'sạch' một.)
grawity

23

Bạn có thể sửa đường ống bị hỏng bằng chi phí của một quy trình khác bằng cách chèn tail -n +1vào đường ống của bạn, như thế này:

loại rvm | đuôi -n +1 | đầu -1

Các +1kể tailđể in dòng đầu tiên của đầu vào và tất cả những gì sau. Đầu ra sẽ giống hệt như khi tail -n +1không có ở đó, nhưng chương trình đủ thông minh để kiểm tra đầu ra tiêu chuẩn và đóng ống xuống sạch sẽ. Không còn đường ống bị vỡ .


1
Bí quyết đẹp. Tôi đã sử dụng trong một tình huống khác với tình huống được cung cấp ở đây. Cảm ơn!
Ai đó vẫn sử dụng bạn MS-DOS

6
Trông giống như một giải pháp tuyệt vời, nhưng trên Ubuntu 14.04.2 có đuôi 8.21 tôi nhận được "tail: write error: Broken pipe", không có gì cải thiện.
Roger Dueck

2
@RogerDueck là chính xác. Tôi cũng thấy điều này trên một hệ thống Mandriva cho một loại vấn đề tương tự find /var/lib/mysql -xdev -type f -daystart -mmin +5 -print0 | xargs -0 ls -ldt | tail -n +1 | headđáng tin cậy mang lại xargs: ls: terminated by signal 13. Như chúng ta đã biết, vấn đề là một trong những kiệt sức đầu vào và thực sự chỉ có một lệnh liên quan đến bộ đệm: dd. Thêm | dd obs=1Mvào đường ống sửa chữa SIGPIPE cho trường hợp sử dụng của tôi.
Andrew Beals

3
Tôi sẽ tiếp tục sửa đổi đề xuất của mình, mặc dù tôi sẽ lưu ý rằng tôi không tin rằng xargs hoặc loại nên được tải về SIGPIPE, về điều này: type rvm | (head -1 ; dd of=/dev/null) Tất nhiên, điều này cũng tương tự như các đề xuất khác vì nó khiến tất cả các đầu vào được xử lý , nhưng ddnên là chương trình hiệu quả nhất để xử lý những việc như vậy.
Andrew Beals

3
Bình luận về những người vi phạm SIGPIPE tại đây: mail-index.netbsd.org/tech-userlevel/2013/01/07/msg007110.html
Andrew Beals

2

Các write error: Broken pipetin liên quan đến một quá trình viết rằng cố gắng để ghi vào một đường ống không có độc giả còn lại trên đầu đọc rằng đường ống và các hoàn cảnh đặc biệt mà các SIGPIPEtín hiệu được thiết lập để được bỏ qua hoặc bằng các hiện tại hoặc quá trình cha mẹ. Nếu đó là quy trình cha được đặt SIGPIPEthành bị bỏ qua, thì quy trình con không thể hoàn tác lại trong một vỏ không xen kẽ.

Tuy nhiên, có thể tiêu diệt type rvmkhi head -1chấm dứt bằng cách sử dụng các mạng con rõ ràng. Bằng cách này, chúng ta có thể làm nền type rvm, gửi typepidđến mạng con head -1và sau đó thực hiện một cái bẫy trên EXITđó để tiêu diệt type rvmmột cách rõ ràng.

trap "" PIPE        # parent process sets SIGPIPE to be ignored
bash                # start child process
export LANG=C
# create a fake rvm function
eval "
rvm() {
$(printf 'echo line of rvm code %s\n' {1..10000})
}
"

# rvm is a function
# bash: type: write error: Broken pipe
type rvm | head -1

# kill type rvm when head -1 terminates
# sleep 0: do nothing but with external command
( (sleep 0; type rvm) & echo ${!} ; wait ${!} ) | 
    (trap 'trap - EXIT; kill "$typepid"; exit' EXIT; typepid="$(head -1)"; head -1)

Từ câu trả lời của grawity: typecó đủ thời gian để thông báo viết thất bại, dịch mã lỗi và thậm chí in thông báo lỗi sang stderr trước khi bị SIGPIPE giết . Tôi nghĩ rằng giải pháp của bạn không ngăn cản quá trình sản xuất ( typeở đây) phản ứng với việc viết không thành công (do đường ống kín), phải không?
Piotr Dobrogost
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.