ทำไมคำสั่งบางคำสั่ง 'แฮงค์' เทอร์มินัลจนกว่าจะเสร็จสิ้น


22

บางครั้งคุณเรียกใช้โปรแกรมจาก terminal, พูด, †lxpanel เทอร์มินัลจะไม่ทำให้คุณกลับไปที่พรอมต์มันจะหยุดทำงาน คุณสามารถกดCtrl+ Cเพื่อกลับไปที่พรอมต์ lxpanelแต่ที่จะฆ่า อย่างไรก็ตามการกดAlt+ F2(ซึ่งปรากฏขึ้นที่หน้าต่างเพื่อรับคำสั่ง) และการทำงานจะlxpanelทำงานได้อย่างสวยงาม

ทำไมนี้ อะไรคือความแตกต่างระหว่างการรันคำสั่งจากเทอร์มินัลและจากหน้าต่าง 'run' ที่ปรากฏขึ้นเมื่อคุณกดAlt+ F2?

นี่ lxpanel เพิ่งมีการใช้เป็นตัวอย่าง ฉันเคยเจอสิ่งนี้กับหลาย ๆ โปรแกรม


1
เคล็ดลับ: หน้าจอ GNU ( screen) สามารถใช้เพื่อ "ห่อ" กระบวนการที่ใช้เวลานานขึ้นได้ คุณสามารถแยกออกจากมันกลับไปที่เชลล์จากนั้นใส่กลับเข้าไปใหม่และดูผลลัพธ์จากกระบวนการทำงาน การติดตั้งซ้ำสามารถทำได้จากเทอร์มินัลอื่น SSH เป็นต้นนอกจากนี้ยังอาจมีโปรแกรมอื่น ๆ ที่ให้คุณทำสิ่งนี้
poplitea

คำตอบ:


28

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

$ lxpanel &

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

บางโปรแกรม (โดยทั่วไปคือ daemons) จะแยกกระบวนการแยกต่างหากเมื่อเริ่มต้นแล้วปล่อยให้กระบวนการหลักออกจากโปรแกรมทันที นี่จะทำให้โปรแกรมทำงานต่อไปโดยไม่ปิดกั้นเชลล์ของคุณ


ดังนั้นระบบจะทำอย่างไรเมื่อคุณเรียกใช้โปรแกรมผ่านหน้าต่าง 'เรียกใช้' โดยการกด Alt + f2 (อย่างน้อยใน gnome และ openbox, alt + f2 ทำเช่นนั้น) ฉันถามเพราะทันทีที่คุณพิมพ์คำสั่งโปรแกรมจะเริ่มและกล่องหายไป มันเป็นแค่การเพิ่ม & ไปหรือไม่
sqram

2
@lyrae: โดยค่าเริ่มต้นเชลล์รอให้โปรแกรมดำเนินการให้เสร็จสิ้นก่อนที่จะดำเนินการต่อเซสชันเชลล์ต่อไปจะไม่ "หยุด" โดยคำจำกัดความของ "hang" ใด ๆ alt + f2 ไม่รอให้โปรแกรม เหตุผลที่เชลล์รอให้โปรแกรมดำเนินการให้เสร็จสมบูรณ์เพราะเชลล์สามารถเปลี่ยนทิศทางสิ่งที่ผู้ใช้พิมพ์ลงในเชลล์ไปยังอินพุตมาตรฐานของโปรแกรมและ / หรือแสดงเอาต์พุตมาตรฐานของโปรแกรม เนื่องจาก alt + f2 ใช้เป็นหลักในการเริ่มโปรแกรม GUI, alt + f2 ไม่ได้ให้ความเป็นไปได้ในการใช้อินพุต / เอาต์พุตมาตรฐานดังนั้นจึงไม่จำเป็นต้องรอ
Lie Ryan

1
@lyrae: alt + f2 ไม่ได้ทำอะไรเป็นพิเศษเพื่อเริ่มโปรแกรมในพื้นหลัง; มันคือเชลล์ที่ทำสิ่งพิเศษเพิ่ม '&' เป็นฟังก์ชันของเชลล์ เมื่อเริ่มต้นคำสั่งโดยไม่มี '&' เชลล์จะเปลี่ยนทิศทางอินพุตมาตรฐานของโปรแกรมไปยังอินพุตมาตรฐานของตนเองและเอาต์พุตมาตรฐานของโปรแกรมไปยังเอาต์พุตมาตรฐานของตัวเอง -C เพื่อส่งคำสั่งสัญญาณ SIGINT ไปยังโปรแกรมเบื้องหน้า) เครื่องหมาย '&' บอกให้เชลล์ไม่ทำเช่นนั้นและเพียงแค่เริ่มโปรแกรม (เช่นเดียวกับที่วางแผนไว้)
Lie Ryan

1
@LieRyan บางสิ่งที่คุณพูดว่าเชลล์ใช้ในการจัดการโดยไดรเวอร์ของเคอร์เนลและ "with &" โดยทั่วไปแล้วจะเป็น "พิเศษ" มากกว่า "ไม่มี" โดยนอกเหนือจากที่เชลล์เรียกรอ () [หรือ waitpid หรือเทียบเท่า] ซึ่งไม่ได้ทำโดย alt-f2
Random832

6

เมื่อคุณเริ่มโปรแกรมในเทอร์มินัลเทอร์มินัลจะ "หยุด" จนกว่าโปรแกรมของคุณจะหยุด โดยการกดCtrl+ cคุณกำลังปิดโปรแกรมของคุณและกลับไปที่พรอมต์ คุณจะเห็นสิ่งนี้กับแอพ GUI ทั้งหมดลองใช้ Firefox เป็นต้น

เมื่อคุณใช้วิธีอื่นเช่น Alt + F2 หรือคลิกผ่านเมนูโปรแกรมของคุณจะเริ่มทำงานในพื้นหลังดังนั้นจึงไม่มีอะไรแปลก ๆ เกิดขึ้น (และไม่มีพรอมต์คำสั่งอยู่แล้ว)

หากคุณยังต้องการเปิดใช้แอป GUI จากเทอร์มินัลให้ผนวก&ท้ายคำสั่งของคุณเช่นนั้น

lxpanel &

สิ่งนี้บอกให้เทอร์มินัลทำงานlxpanelในพื้นหลังและให้พรอมต์อื่นทันที


3

โปรแกรมที่ทำงานผ่านเชลล์ที่รันในส่วนหน้าของเชลล์นั้นเป็นค่าเริ่มต้น สิ่งนี้ทำให้เชลล์หยุดการทำงานชั่วคราวและสั่ง stdin / stdout / sterr โดยตรงจากเทอร์มินัลไปยังโปรแกรม โปรแกรมที่ทำงานผ่านสภาพแวดล้อมเดสก์ท็อปจะถูกแยกออกซึ่งทำให้โปรแกรมทำงานโดยไม่ขึ้นกับโปรแกรมที่รัน สิ่งนี้สามารถจำลองได้ในเชลล์ส่วนใหญ่โดยต่อท้าย&คำสั่งถึงแม้ว่าสิ่งนี้จะยังคงเชื่อมต่อ std * กับเทอร์มินัล (แม้ว่าการอ่านจาก stdin บนโปรแกรมที่มีแบ็คกราวน์นั้น


2

ภูมิหลัง & ดียกเว้นสำหรับโปรแกรมที่กลับมาซึ่งต้องมีการโต้ตอบกับคอนโซลในภายหลัง (ตัวอย่างเช่น "apt -y update &" ซึ่งในที่สุดก็เข้าสู่สถานะ STOP เนื่องจากต้องการให้ผู้ใช้ถามคำถาม "บังคับจริง ๆ " ในภายหลัง .... เมื่อไม่มีใครดูอีกแล้ว)

เมื่อต้องการเสียบรูนั้นและแจ้งให้ทราบว่ากระบวนการใดเทอร์มินัลจะไม่สามารถใช้งานได้จริงฉันผนวก <& - ลงในคำสั่งบางคำสั่งของฉันโดยแยกออกจากเทอร์มินัลที่ทำงานอยู่ ตรวจสอบให้แน่ใจ / bin / bash เป็นเชลล์ของคุณหากคุณใช้ สคริปต์จะดำเนินการบันทึกข้อผิดพลาดใด ๆ ที่เกี่ยวข้องกับการไม่มีการแฝงตัวปลอมซึ่งจะทำให้เกิดพรอมต์ใด ๆ

ตัวอย่างเช่น:

`./runme.sh &> runme.log <&- & disown`

เป็นวิธีที่ดีที่สุดของฉันในการยกเลิกการเชื่อมโยงจากเซสชันเทอร์มินัลปัจจุบัน ทั้ง STDOUT และ STDERR เข้าสู่ runme.log มันจะไม่สำคัญว่าคอนโซลหรือเชลล์ของคุณจะยุติลงเร็วกว่านี้หรือถ้าคุณออกจากระบบ / su ไปยังบัญชีอื่น (ไม่มีเทอร์มินัลขยะจาก runme) และต้องขอบคุณแม้แต่ผู้ปกครอง ความสัมพันธ์ PID จะถูกลบออก

UPDATE: แม้ว่าฉันจะมีปัญหากับสัญญาณที่เชื่อมโยงกับชื่อของผู้ปกครองดั้งเดิมดังนั้นตอนนี้ฉันขอแนะนำแทน:

at now <<< "(cmd1; cmd2; etc.) &> logfile.log"

แน่นอนลบ &> หากคุณต้องการรับอีเมลจาก CRON หรือเปลี่ยนเส้นทางทั้งหมดเป็น / dev / null แทนที่จะเป็นไฟล์


วิธีที่ซับซ้อนน้อยกว่าเพื่อให้บรรลุที่ฉันเริ่มใช้คือat now <<< "(cmd1; cmd2; etc.) &> logfile.log"
Marcos
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.