การหยุดเอาต์พุตจากโปรแกรมที่รันในเซสชัน SSH ทันที


18

ปัญหา

ฉันรันคำสั่งที่ให้เอาท์พุตจำนวนมากของข้อมูลผ่าน SSH ตัวอย่างเช่นฉันเพิ่มข้อมูลการดีบักภายในลูปที่ดำเนินการเป็นล้านครั้งหรือเพียงแค่วิ่งcat /dev/urandomเพื่อเตะ

ข้อมูลถูกเทอร์มินัล

ตัวอย่างสิ่งที่ฉันพูดถึง

ฉันต้องการยุติคำสั่งโดยเร็วและแก้ไขโปรแกรมของฉัน ฉันไม่สนใจสิ่งที่จะพิมพ์ ตอนนี้สิ่งที่ผมกดCtrl+ Cที่เร็วที่สุด (ในตัวอย่างข้างต้นผมกดมันทันทีหลังจากใช้คำสั่ง) แต่ก็ยังคงต้องใช้เวลาในการพิมพ์ข้อมูลทั้งหมดที่ฉันไม่จำเป็นต้อง

สิ่งที่ฉันได้ลอง

ฉันลองกดCtrl+ Cอย่างหนักเพื่อให้ได้ผลลัพธ์ที่ตลกเมื่อท้ายสุดเทอร์มินัล:

OUTPUT HERE^C
rr-@burza:~/xor$ ^C
rr-@burza:~/xor$ ^C
rr-@burza:~/xor$ ^C
^C^C

^C^C^C^C^C^C^C^C^C^C^C
^C^C^C^C^C^C^C^C^C^C
^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C
^C^C^C^C^C^C^C
^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C
^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C^C
^C^C^C^C^C^C^C^C^C^C^C^C^C
rr-@burza:~/xor$ ^C
rr-@burza:~/xor$ ^C
rr-@burza:~/xor$ ^C
rr-@burza:~/xor$ ^C
rr-@burza:~/xor$ ^C
rr-@burza:~/xor$ ^C
rr-@burza:~/xor$ ^C
rr-@burza:~/xor$ ^C
rr-@burza:~/xor$ ^C

ฉันยังอ่านเกี่ยวกับCtrl+ Sซึ่งเห็นได้ชัดว่าใช้เพื่อบอกเทอร์มินัล "หยุดส่งออกฉันต้องทัน"แต่เห็นได้ชัดว่าไม่ได้ทำอะไรเลย

รายละเอียดเบ็ดเตล็ด

ฉันไม่ต้องการเปลี่ยนคำสั่งที่ฉันเรียกใช้เพื่อที่ฉันจะสามารถช่วยเหลือตัวเองได้ในทุกสถานการณ์แม้ว่าฉันจะจำไม่ได้ว่าโปรแกรมที่ฉันรันอาจจบลงเช่นนั้น

ลูกค้า SSH ของฉันทำงานบน Cygwin ( CYGWIN_NT-6.1-WOW64 luna 1.7.30(0.272/5/3) 2014-05-23 10:36 i686 Cygwin) ใน MinTTY xterm-256colorกับชุดประเภทอาคารเพื่อ

เซิร์ฟเวอร์ SSH ทำงานบน Debian ( Linux burza 3.2.0-4-686-pae #1 SMP Debian 3.2.51-1 i686 i686 i686 GNU/Linux)


คุณใช้ระบบใดในโปรแกรมจริงที่สร้างเอาต์พุต Linux, Unix หรือ Windows Linux และ UNIX ควรยอมรับCtrl-Oซึ่งหมายความว่า "ยกเลิกเอาต์พุตใด ๆ ที่เขียนไปยังเทอร์มินัลนี้"
Mark Plotnick

เซิร์ฟเวอร์ทำงานบน Debian แก้ไขคำถาม Ctrl-O ดูเหมือนจะไม่ทำอะไรเช่นกัน บางทีมันเป็นสิ่งที่ลูกค้า?
rr-

คุณอาจลองเริ่มต้น xterm ด้วย-jตัวเลือกเพื่อเปิดใช้งานการเลื่อนแบบข้าม ปัญหาพื้นฐานคือรีโมตสามารถส่งข้อมูลได้เร็วกว่าหน้าต่างเทอร์มินัลที่สามารถแสดงได้ - โดยค่าเริ่มต้นจะต้อง bitblt เนื้อหาของหน้าต่างทุกครั้งที่พิมพ์บรรทัดใหม่ ข้อมูลจำนวนมากสามารถถูกบัฟเฟอร์ในเวลาที่ Ctrl-C ของคุณได้รับจากระบบรีโมตและโปรแกรมเทอร์มินัลของคุณจะพยายามแสดงข้อมูลทั้งหมด
Mark Plotnick

แค่ความคิด: ถ้าคุณมีคำสั่งที่แน่นอนที่คุณมักจะเรียกใช้โดยไม่ได้ตั้งใจและพวกมันสร้างเอาต์พุตจำนวนมากทำไมไม่เพียงแค่ต่อนามแฝงต่อท้าย.bashrc?
psimon

คุณสามารถใช้ mosh แทน ssh: mosh.mit.edu
gmatht

คำตอบ:


5

เอาต์พุตบางส่วนนั้นจะถูกบัฟเฟอร์ คุณส่งCtrl+ ของคุณCไปยังปลายทางระยะไกลซึ่งขัดจังหวะโปรแกรมที่กำลังทำงานอยู่ มีโปรแกรมอยู่และเชลล์ส่งอักขระเพื่อแสดงพรอมต์ให้คุณอีกครั้ง ก่อนที่จะมีข้อความแจ้งปรากฏขึ้นหน้าจอของคุณจะแสดงข้อมูลทั้งหมดที่ได้รับการบัฟเฟอร์ก่อน

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

วิธีเดียวที่คุณสามารถตรวจสอบให้แน่ใจว่าคุณไม่เห็นข้อมูลนี้คือออกจากเทอร์มินัลเมื่อสิ้นสุดการเชื่อมต่อกับรีโมตของคุณอีกครั้ง แต่นั่นอาจเป็นความพยายามมากกว่ารอให้บัฟเฟอร์ข้อมูลแสดง


10

ฉันมักจะเรียกใช้ผลลัพธ์เป็นlessเพื่อให้ฉันสามารถฆ่ามันผ่านlessแทนการใช้qปุ่ม

$ cmd | less

ตัวอย่าง

$ cat /dev/urandom | less

   เอสเอส # 2

หลังจากกดปุ่มq+ Enterมันจะออกและกลับไปที่หน้าจอปกติของคุณทิ้งไว้ให้ดีและสะอาด

ทำไมถึงเกิดขึ้น?

ปัญหาที่คุณพบคือมีบัฟเฟอร์ (สำหรับ STDOUT) ที่อยู่ในคิวด้วยเอาต์พุตของจอแสดงผลของคุณ บัฟเฟอร์เหล่านี้จะถูกเติมเต็มอย่างรวดเร็วจนคุณไม่สามารถหยุดมันได้เร็วพอที่จะหยุดมันได้

                                    เอสเอส # 1

ในการปิดการใช้งาน / จำกัด เอฟเฟกต์นี้คุณสามารถปิดการใช้งานบัฟเฟอร์ STDOUT ซึ่งควรทำให้การตอบสนองการใช้เพิ่มขึ้นเล็กน้อยstdbufแต่คุณอาจต้องเล่นกับการตั้งค่าเหล่านี้เพื่อให้ได้สิ่งที่ต้องการ หากต้องการ unbuffer STDOUT คุณสามารถใช้คำสั่งนี้:

$ stdbuf -o0 <cmd>

หน้าคนเพื่อstdbufดูรายละเอียดตัวเลือกต่าง ๆ ที่คุณต้องการ:

    If MODE is 'L' the corresponding stream will be line buffered.  This 
    option is invalid with standard input.

    If MODE is '0' the corresponding stream will be unbuffered.

    Otherwise MODE is a number which may be followed by one of the 
    following: KB 1000, K 1024, MB 1000*1000, M 1024*1024, and so
    on for G, T, P, E, Z, Y.  In this case the corresponding stream will be 
    fully buffered with the  buffer  size  set  to  MODE
    bytes.

สำหรับพื้นหลังที่ดีเกี่ยวกับวิธีการทำงานบัฟเฟอร์ผมขอแนะนำการดูที่จังหวะพิกเซลนี้ฝึกหัดชื่อ: บัฟเฟอร์ในลำธารมาตรฐาน มันยังรวมถึงรูปภาพที่ดี

อ้างอิง


นั่นเป็นเหตุผลตราบใดที่คุณจำได้ว่าต้องผนวก|lessเข้าcmdด้วยกัน ถ้าคุณเรียกคุณยังคงต้องรอจนกว่าจะมีผลการพิมพ์เสร็จแล้วคำนวณไว้ก่อนที่ได้รับcmd ^C
rr-

1
แต่นั่นไม่ได้อธิบายว่าเกิดอะไรขึ้น ท้ายที่สุดแล้วไม่มีส่วนเกี่ยวข้องใด ๆ กับบัฟเฟอร์ดังนั้นคุณอ้างอิงถึงบัฟเฟอร์อะไร
Gilles 'ดังนั้น - หยุดความชั่วร้าย'

@Gilles - ขออภัยบัฟเฟอร์จะเป็นบัฟเฟอร์ไปยังหน้าจอ
slm

บัฟเฟอร์อะไร ในเคอร์เนล? ใน xterm
Gilles 'หยุดความชั่วร้าย'

@Gilles - ให้ฉันสักครู่ฉันกำลังมองหารายละเอียด 8-)
slm

3

การบัฟเฟอร์มีหลายระดับ เมื่อคุณกดCtrl+ Cสิ่งนี้จะหยุดโปรแกรมจากการส่งข้อมูลไปยังเทอร์มินัล สิ่งนี้ไม่ส่งผลกระทบต่อข้อมูลที่เทอร์มินัลอีมูเลเตอร์ยังไม่แสดง

เมื่อคุณแสดงข้อมูลด้วยความเร็วสูงเทอร์มินัลไม่สามารถติดตามและจะล้าหลัง นั่นคือสิ่งที่เกิดขึ้นที่นี่: การแสดงข้อความมีราคาแพงกว่าการสร้างตัวเลขสุ่มเหล่านี้ ใช่แม้จะมีตัวอักษรบิตแมป - การสร้างตัวเลขสุ่มที่มีคุณภาพการเข้ารหัสลับนั้นก็ไม่ถูกเมื่อเทียบ (ฉันเพิ่งลองบนเครื่องของฉันและกระบวนการ X ทำให้ซีพียูอิ่มตัวโดยxtermใช้เวลาเพียงไม่กี่% และcat(ซึ่งการสุ่มหมายเลขจะถูกนับรวม) แทบจะถึง 1% และนั่นก็เป็นแบบอักษรบิตแมป)

ถ้าคุณต้องการให้มันหยุดตอนนี้ให้ฆ่า terminal emulator หากคุณไม่ต้องการที่จะทำอย่างน้อยที่สุดลดหน้าต่าง; ตัวเลียนแบบเทอร์มินัลอัจฉริยะ (เช่น xterm) จะไม่แมปหน้าต่างซึ่งช่วยประหยัดเวลาของ CPU X ดังนั้นขยะจะแสดงเสร็จเร็วขึ้น เซิร์ฟเวอร์ X มีลำดับความสำคัญสูงดังนั้นสิ่งนี้จะสร้างความแตกต่างอย่างมากต่อการตอบสนองของเครื่องของคุณในขณะที่ xterm กำลังประมวลผลข้อมูลในพื้นหลัง

เมื่อสิ่งนี้เกิดขึ้นในเปลือกระยะไกลความล่าช้าจะยิ่งแย่ลงเพราะข้อมูลที่ผลิตโดยcatจะต้องผ่านการเชื่อมต่อ SSH การกดCtrl+ Cจะต้องผ่านการเชื่อมต่อ SSH จะได้รับลำดับความสำคัญค่อนข้างสูง (ส่งออกนอกวง) แต่ยังคงต้องใช้เวลาพอสมควรในระหว่างที่มีเอาต์พุตสะสมมากขึ้น ไม่มีทางที่จะระงับข้อมูลในระหว่างการขนส่งสั้น ๆ ของการปิดการเชื่อมต่อ SSH (ซึ่งคุณสามารถทำได้โดยการกดEnterแล้ว~.)


ปัญหาเกี่ยวข้องกับ SSH ตามมา ไม่ควรใช้บัฟเฟอร์ STDOUT ในโหมดโต้ตอบ แต่ SSH ไม่สามารถจัดการโหมดโต้ตอบได้อย่างถูกต้อง แม้ว่าเอาต์พุตจำนวนมากอาจหยุดทำงานในธุรกรรม แต่เป็นกระบวนการ SSH ซึ่งได้รับ Ctrl + C ดังนั้นจึงเป็นความรับผิดชอบของเขาในการฆ่าเอาต์พุตเมื่อไม่สามารถส่งผ่าน Ctrl + C ไปยังรีโมตได้
user4674453

@ user4674453 เอ๊ะ? Ctrl + C ไม่ควรฆ่าเอาต์พุตในเครื่อง นั่นไม่ใช่งานของมันเลย มันควรจะถูกส่งผ่านไปยังด้านระยะไกลซึ่งอาจหรืออาจจะไม่ฆ่ากระบวนการระยะไกล
Gilles 'หยุดความชั่วร้าย' ใน

"มันควรจะถูกส่งผ่านไปยังด้านรีโมตซึ่งอาจหรืออาจจะไม่ฆ่ากระบวนการรีโมต" - ไม่ควรทำเช่นนั้น สัญญาณ KILL, Ctrl + C กำลังออกหนึ่งในนั้นสำหรับกระบวนการโลคัลเท่านั้น ถ้ามันไม่ได้ใช้สำหรับกระบวนการในท้องถิ่นความคิดของ "ที่ควรจะ" ไม่สามารถใช้ได้เลย
user4674453

@ user4674453 ไม่ Ctrl + C ไม่ใช่สัญญาณ kill มันเป็นสัญญาณขัดจังหวะ บทบาทของมันคือการกลับไปที่พรอมต์แบบโต้ตอบ มันฆ่าโปรแกรมที่ไม่มีพรอมต์โต้ตอบเพื่อกลับไปเท่านั้น
Gilles 'หยุดความชั่วร้าย' ใน

"มันเป็นสัญญาณขัดจังหวะ" มันเป็นข้อโต้แย้งที่จะฆ่าคำสั่งดังนั้นมันจึงเป็นสัญญาณการฆ่า บางครั้งมันถูกเรียกว่าเป็นสัญญาณ POSIX หากคุณต้องการ "บทบาทของมันคือการกลับไปที่พรอมต์แบบอินเทอร์แอกทีฟมันฆ่าโปรแกรมที่ไม่มีพรอมต์แบบโต้ตอบเท่านั้นที่จะกลับไป" แน่นอน !!! และ SSH ก็ไม่ทำตามที่คาดไว้
user4674453

1

มันควรจะเพียงพอที่จะหาวิธีkillการcatคำสั่ง
สำหรับข้อเสนอต่อไปนี้คุณอาจต้องเปิดการเชื่อมต่อ ssh ที่สอง

  • ไม่ค่อยCTRL+zมีประสิทธิภาพมากกว่าCTRL+c: สามารถตอบได้เร็วขึ้น หลังจากนั้นคุณระงับคำสั่งคุณสามารถฆ่ามันด้วยkill %1หรือจำนวนงานของมันคืออะไร
    ด้วยความหวังว่าคุณจะยังคงสามารถอ่านอะไรได้จากหน้าจอ (ข้อความไบนารีแบบสุ่มที่ท่วมท้นสามารถทำให้ชุดตัวละครของคุณเสียไป)
    ตามที่Gillesจดจำไว้หากคุณย่อขนาดหน้าต่างให้เล็กที่สุดระบบจะเร็วกว่าที่จะอ่านคำขอขัดจังหวะมากกว่าที่คุณจะฆ่ากระบวนการ ดังนั้นพัก / หยุดย่อย่อรอสักครู่เพิ่มอีกครั้งสามารถแก้ไขได้เช่นกัน
    แน่นอนผ่านการเชื่อมต่อ SSH ฉันคาดหวังว่าคุณจะต้องรอสักครู่

  • ในเทอร์มินัล / เซสชันอื่นคุณสามารถถามpgrep cat(ถ้า cat เป็นคำสั่งที่เรียกใช้) และระบุว่ากระบวนการ cat กำลังใช้ cpu ของคุณมากขึ้น คุณสามารถระบุด้วยความแม่นยำมากขึ้นด้วยpstree:

    pgrep cat | awk '{พิมพ์ "pstree -sp" $ 1}' | sh | grep sshd

    ตอบด้วยผลลัพธ์เช่น

    init (1) ───sshd (1062) ───sshd (22,884) ───sshd (22,951) ───bash (22,957) ───cat (23,131)

    ในกรณีนี้หลังจากคุณเพียงฆ่าแมว PID: ฆ่า 23131

บันทึก:


1

ฉันมีปัญหาเดียวกันและไม่พอใจกับคำตอบที่นี่ดังนั้นฉันจึงขุดลึกลงไป ผู้อื่นได้กล่าวถึงคำสั่งของคุณแล้วว่ากำลังส่งออกข้อมูลเร็วกว่าที่ ssh สามารถรับได้ดังนั้นบัฟเฟอร์ข้อมูลและบัฟเฟอร์ไม่สามารถหยุดได้

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

การตั้งค่าขั้นแรกให้หาอัตราสูงสุดของเซสชันของคุณ:

# Get transfer <TIME> of a large file (>10MB preferable)
/usr/bin/time -f "%e" cat <FILENAME>

# Get file <SIZE> in bytes
stat --printf="%s\n" <FILENAME>

# Calculate <RATE>
echo "<SIZE> / <TIME>" | bc

ในที่สุดให้เร่งคำสั่งจริงของคุณตามนั้น

<YOUR_COMMAND> | pv -qL <RATE>

ตัวอย่าง:

/usr/bin/time -f "%e" cat large_reference_file.txt
31.26

stat --printf="%s\n" cat large_reference_file.txt
17302734

echo "17302734 / 31.26" | bc
553510

# Throttle my command to 553510B/s
cat some_other_file.txt | pv -qL 553510

คุณอาจต้องการลดอัตราเล็กน้อยในกรณีที่ความเร็วการเชื่อมต่อของคุณลดลงเล็กน้อยเป็นครั้งคราว ถ้ามันลดลงพฤติกรรมจะกลับมาเป็น ctrl-c ที่ไม่ตอบสนอง

นามแฝงแมวชนิดเสริม

# bash
alias tcat='tcat(){ cat $@ | pv -qL 400k ; }; tcat'

# tcsh
alias tcat 'cat \!* | pv -qL 400k'

# usage: tcat <FILENAME>

ตอนนี้ ctrl-c ทำงานได้ตามที่คาดไว้ฆ่าผลทันทีเพราะมีบัฟเฟอร์น้อยมาก


catผลลัพธ์ไม่ค่อยมีปัญหาซึ่งแตกต่างจากซอฟต์แวร์อื่น ๆ ผู้เขียนใช้มันเป็นตัวอย่างเท่านั้น ปัญหานี้มักจะเกิดจากซอฟต์แวร์อื่น ๆ ซึ่งอาจไม่ชัดเจนถ้ามันเต็มใจที่จะผลิตผลลัพธ์จำนวนมาก การใช้คำสั่ง prefix หรือ postfix ใด ๆ นั้นไม่มีวิธีแก้ปัญหาเนื่องจากต้องใช้เวลาในการพิมพ์ จะไม่มีผลกำไรใด ๆ เกิดขึ้น
user4674453

0

มีซอฟต์แวร์บน Linux ซึ่งแก้คือตรงนี้ปัญหา (สองสิ่งที่คนอื่น ๆ มากเกินไป) คุณสามารถเรียกใช้งานจากเทอร์มินัลอีมูเลเตอร์ใน Windows (ดูเหมือนว่าคุณกำลังใช้ Windows?)

ลองmoshแทนการใช้ไบนารี SSH มันทำงานเหมือนกับ SSH (คุณสามารถทำได้mosh user@hostnameแทนssh user@hostnameและมันจะทำงานได้ตามที่คุณคาดหวังแม้จะทำการตรวจสอบคีย์ส่วนตัว ฯลฯ

โดยทั่วไปแล้วจะดำเนินกระบวนการแยกต่างหากบนเซิร์ฟเวอร์ซึ่งบัฟเฟอร์แพ็คเก็ต ดังนั้นเมื่อคุณกด Ctrl + C บน mosh มันจะถ่ายทอดสิ่งนี้ไปยังเซิร์ฟเวอร์ระยะไกลซึ่งจะหยุดส่งข้อมูลพิเศษ นอกจากนี้มันยังจะทำนายผลลัพธ์ของการกดแป้นพิมพ์ช่วยให้คุณประหยัดเวลาสองสามมิลลิวินาทีทุกครั้งที่คุณกดปุ่ม

ข้อเสีย: ขณะนี้ไม่สามารถเลื่อนขึ้นในประวัติศาสตร์ขณะใช้ mosh

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.