ฉันจะแก้ไขข้อผิดพลาด Broken Pipe ได้อย่างไร


36

ฉันเพิ่งติดตั้ง RVM ใหม่ (ทำตามคำแนะนำที่http://rvm.io ) หลังจากติดตั้ง Ubuntu 12.10 ใหม่เมื่อฉันได้รับ SSD Drive

ตอนนี้เมื่อฉันพิมพ์: type rvm | head -1

ฉันได้รับข้อผิดพลาดต่อไปนี้:

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

แต่ถ้าฉันทำซ้ำคำสั่งทันทีฉันก็จะได้รับ:

rvm is a function

และดูเหมือนว่าทุกอย่างก็โอเค เกิดอะไรขึ้น? ฉันจะแก้ไขได้อย่างไร มันไม่ได้เกิดขึ้นเสมอไป มันดูเหมือนจะเป็นระยะ ๆ ฉันพยายามที่จะหารูปแบบบางอย่าง แต่ยังไม่ได้

คำตอบ:


57

การดู "ท่อแตก" ในสถานการณ์เช่นนี้หายาก แต่ปกติ

เมื่อคุณรันtype rvm | head -1bash จะทำงานtype rvmในกระบวนการหนึ่งในอีกกระบวนการhead -1หนึ่ง 1 stdout ของtypeการเชื่อมต่อกับ "การเขียน" ปลายท่อ , stdin ของheadที่ "อ่าน" สิ้น กระบวนการทั้งสองทำงานในเวลาเดียวกัน

head -1กระบวนการอ่านข้อมูลจาก stdin (โดยปกติในชิ้น 8 KB), ที่พิมพ์ออกมาเป็นเส้นเดียว (ตาม-1ตัวเลือก) และทางออกที่ก่อให้เกิด "อ่าน" ปลายท่อที่จะปิด เนื่องจากrvmฟังก์ชั่นค่อนข้างยาว (ประมาณ 11 kB หลังจากถูกแยกวิเคราะห์และสร้างใหม่โดยการทุบตี) ซึ่งหมายความว่าheadจะออกในขณะที่typeยังคงมีข้อมูลไม่กี่กิโลไบต์ที่จะเขียนออกมา

ณ จุดนี้เนื่องจากtypeพยายามเขียนไปยังไพพ์ที่ปลายอีกด้านหนึ่งถูกปิด - ไพพ์ที่ขาด - ฟังก์ชั่น write () ที่ caled จะส่งคืนข้อผิดพลาด EPIPE ซึ่งแปลว่า "ไพพ์ไพพ์" นอกเหนือจากข้อผิดพลาดนี้เคอร์เนลยังส่งสัญญาณ SIGPIPE ไปให้typeซึ่งโดยค่าเริ่มต้นจะฆ่ากระบวนการทันที

(สัญญาณมีประโยชน์อย่างมากในเชลล์เชิงโต้ตอบเนื่องจากผู้ใช้ส่วนใหญ่ไม่ต้องการให้กระบวนการแรกทำงานต่อไปและพยายามเขียนถึงที่ใด ๆ ในขณะเดียวกันบริการที่ไม่โต้ตอบไม่สนใจ SIGPIPE - มันจะไม่ดีสำหรับ daemon ที่ทำงานมายาวนาน ตายบนข้อผิดพลาดง่าย ๆ - พวกเขาพบว่ารหัสข้อผิดพลาดมีประโยชน์มาก)

อย่างไรก็ตามการส่งสัญญาณไม่ได้ 100% ทันทีและอาจมีบางกรณีที่ write () ส่งคืน EPIPE และกระบวนการยังคงทำงานต่อไปชั่วครู่ก่อนที่จะรับสัญญาณ ในกรณีนี้ให้typeมีเวลามากพอที่จะสังเกตเห็นว่าการเขียนล้มเหลวแปลรหัสข้อผิดพลาดและแม้แต่พิมพ์ข้อความแสดงข้อผิดพลาดไปยัง stderr ก่อนที่ SIGPIPE จะถูกฆ่า (ข้อความแสดงข้อผิดพลาดแจ้งว่า "-bash: type:" เนื่องจากtypeเป็นคำสั่งในตัวของ bash เอง)

สิ่งนี้ดูเหมือนว่าจะพบได้บ่อยในระบบหลายซีพียูเนื่องจากtypeกระบวนการและรหัสการส่งสัญญาณของเคอร์เนลสามารถทำงานบนแกนที่แตกต่างกันในเวลาเดียวกัน

เป็นไปได้ที่จะลบข้อความนี้โดยการติดตั้งtypebuiltin (ในซอร์สโค้ดของ bash) เพื่อออกทันทีเมื่อได้รับ EPIPE จากฟังก์ชัน write ()

อย่างไรก็ตามไม่มีอะไรที่ต้องกังวลและไม่เกี่ยวข้องกับการrvmติดตั้งของคุณแต่อย่างใด


ขอขอบคุณ! ฉันเป็นห่วงเกี่ยวกับเรื่องนี้ ฉันใช้เวลาประมาณหนึ่งชั่วโมงในการแก้ไขปัญหา googling เมื่อคืนนี้เพื่อแก้ไขปัญหาการติดตั้ง rvm ของฉันและทำการซ่อมแซมเพื่อพยายามแก้ไข ฉันแค่สลับกับไดรฟ์ SSD และใช้ LVM และเข้ารหัสฮาร์ดไดรฟ์เพื่อให้มีตัวแปรมากมายที่เข้ามาเล่นและฉันไม่แน่ใจว่าสิ่งที่อาจเกิดขึ้นไปด้านข้าง ขอบคุณที่ทำให้ฉันสบายใจ!
Jason Shultz

ฉันได้ส่งออกท่อของlsผ่านhead -1มานานหลายปีและวันนี้ฉันได้รับข้อความท่อแตก
Tulains Córdova

1
(หมายเหตุ: ข้อผิดพลาด "ท่อแตก" ไม่ได้มาจากสัญญาณมันมาจากerrnoในขณะที่เชลล์อาจแสดงข้อความตัวอักษรสำหรับการเหนี่ยวนำสัญญาณออกโดยปกติจะฉลาดพอที่จะแสร้งว่าทางออก SIGPIPE เป็น หนึ่ง 'สะอาด')
grawity

23

คุณสามารถแก้ไขไปป์ที่เสียค่าใช้จ่ายของกระบวนการอื่นโดยการแทรกลงtail -n +1ในไพพ์ของคุณเช่นนี้

พิมพ์ rvm | tail -n +1 | หัว -1

การ+1บอกtailให้พิมพ์บรรทัดแรกของอินพุตและทุกอย่างที่ตามมา เอาต์พุตจะเหมือนกันกับที่tail -n +1ไม่ได้มี แต่โปรแกรมนั้นฉลาดพอที่จะตรวจสอบเอาต์พุตมาตรฐานและปิดไพพ์ลงอย่างหมดจด ไม่มีรายละเอียดเพิ่มเติมท่อเสีย


1
เคล็ดลับดี ฉันใช้ในสถานการณ์ที่แตกต่างจากที่ระบุไว้ที่นี่ ขอบคุณ!
บางคนยังคงใช้ MS-DOS ของคุณ

6
ดูเหมือนว่าเป็นทางออกที่ดี แต่ใน Ubuntu 14.04.2 ด้วย tail 8.21 ฉันได้รับ "tail: write error: Broken pipe" ซึ่งไม่มีการปรับปรุง
Roger Dueck

2
@RogerDueck ถูกต้อง ฉันยังเห็นนี้ในระบบ Mandriva สำหรับการจัดเรียงที่คล้ายกันของปัญหาอัตราผลตอบแทนได้อย่างน่าเชื่อถือfind /var/lib/mysql -xdev -type f -daystart -mmin +5 -print0 | xargs -0 ls -ldt | tail -n +1 | head xargs: ls: terminated by signal 13ดังที่เราทราบปัญหาคือหนึ่งในความอ่อนล้าของอินพุตและมีคำสั่งเดียวเท่านั้นที่เกี่ยวข้องกับการบัฟเฟอร์: dd การเพิ่ม| dd obs=1Mไปป์ไลน์แก้ไข SIGPIPE สำหรับกรณีการใช้ของฉัน
Andrew Beals

3
ฉันจะแก้ไขข้อเสนอแนะของฉันต่อไปแม้ว่าฉันจะทราบว่าฉันไม่เชื่อว่า xargs หรือประเภทควรเป็นเรื่องเกี่ยวกับ SIGPIPE: type rvm | (head -1 ; dd of=/dev/null) สิ่งนี้แน่นอนคล้ายกับข้อเสนอแนะอื่น ๆ เนื่องจากทำให้อินพุตทั้งหมดถูกประมวลผล แต่ddควรเป็นโปรแกรมที่มีประสิทธิภาพที่สุดในการจัดการสิ่งต่าง ๆ
Andrew Beals

3
ความเห็นเกี่ยวกับผู้ฝ่าฝืน SIGPIPE ได้ที่นี่: mail-index.netbsd.org/tech-userlevel/2013/01/07/msg007110.html
Andrew Beals

2

write error: Broken pipeข้อความหมายถึงขั้นตอนการเขียนที่พยายามที่จะเขียนไปยังท่อกับผู้อ่านไม่เหลือที่สิ้นสุดการอ่านของท่อที่และสถานการณ์พิเศษที่เป็นSIGPIPEสัญญาณที่มีการตั้งค่าที่จะละเลยอย่างใดอย่างหนึ่งโดยปัจจุบันหรือการปกครอง ถ้ามันเป็นกระบวนการหลักที่ตั้งค่าSIGPIPEให้ละเว้นมันเป็นไปไม่ได้สำหรับกระบวนการลูกที่จะเลิกทำเช่นนั้นอีกครั้งในเชลล์ที่ไม่ใช่ interacitive

อย่างไรก็ตามมันเป็นไปได้ที่จะฆ่าtype rvmเมื่อhead -1ยกเลิกโดยใช้ subshells ที่ชัดเจน วิธีนี้เราสามารถแบ็คกราวtype rvmด์ส่งtypepidไปยังhead -1subshell แล้วนำไปใช้กับกับดักEXITเพื่อฆ่าtype rvmอย่างชัดเจน

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)

จากคำตอบของ grawity: typeได้รับเวลามากพอที่จะแจ้งให้ทราบล่วงหน้าเขียนล้มเหลวที่แปลรหัสข้อผิดพลาดและแม้กระทั่งการพิมพ์ข้อความผิดพลาดที่จะ stderr ก่อนที่จะถูกฆ่าตายโดย SIGPIPE ฉันคิดว่าโซลูชันของคุณไม่ได้ป้องกันกระบวนการผู้ผลิต ( typeที่นี่) จากการตอบสนองต่อการเขียนที่ล้มเหลว (เนื่องจากไพพ์ปิด) ใช่ไหม
Piotr Dobrogost
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.