วิธีกำจัดสิ่งรบกวนเมื่อเริ่มต้น GUI จากเทอร์มินัล


14

ฉันต้องการเปิดใช้งานแอปพลิเคชัน GUI จากหน้าต่างเทอร์มินัลแทนที่จะใช้กราฟิกเดสก์ท็อป สิ่งที่น่ารำคาญก็คือบ่อยครั้งที่นักพัฒนาไม่ได้คาดหวังการใช้งานประเภทนี้ดังนั้นแอพจะพิมพ์ข้อความที่ไร้ประโยชน์เป็นความลับหรือไร้ประโยชน์มากมายไปยัง stdout หรือ stderr ความยุ่งเหยิงเพิ่มเติมบนเครื่องเทอร์มินัลเกิดขึ้นเนื่องจากการเรียกใช้โปรแกรมในเบื้องหลังโดยมี & จะสร้างรายงานการสร้างและการยกเลิกงาน

วิธีแก้ปัญหาสำหรับปัญหาเหล่านี้ที่จะยอมรับอาร์กิวเมนต์บรรทัดคำสั่งและจัดการการเติมข้อความอัตโนมัติคืออะไร

ที่เกี่ยวข้อง: /programming/7131670/make-bash-alias-that-takes-parameter

คำตอบ:


15

การเปลี่ยนเส้นทางข้อผิดพลาดมาตรฐานทันที/dev/nullเป็นความคิดที่ไม่ดีเนื่องจากจะซ่อนข้อความแสดงข้อผิดพลาดก่อนและความล้มเหลวอาจยากต่อการวินิจฉัย ฉันขอแนะนำบางอย่างเช่นstart-appสคริปต์ zsh ต่อไปนี้:

#!/usr/bin/env zsh
coproc "$@" 2>&1
quit=$(($(date +%s)+5))
nlines=0
while [[ $((nlines++)) -lt 10 ]] && read -p -t 5 line
do
  [[ $(date +%s) -ge $quit ]] && break
  printf "[%s] %s\n" "$(date +%T)" "$line"
done &

เพียงรันด้วย: start-app your_command argument ...

สคริปต์นี้จะแสดงผลข้อความไม่เกิน 10 บรรทัดและไม่เกิน 5 วินาที อย่างไรก็ตามโปรดทราบว่าหากแอปพลิเคชันหยุดทำงานทันที (เช่นเนื่องจากข้อผิดพลาดในการแบ่งกลุ่ม) คุณจะไม่เห็นข้อความแสดงข้อผิดพลาดใด ๆ แน่นอนคุณสามารถแก้ไขสคริปต์นี้ได้หลายวิธีเพื่อทำสิ่งที่คุณต้องการ ...

หมายเหตุ: หากต้องการทำให้การทำงานให้สำเร็จด้วยstart-appin zsh ก็เพียงพอแล้วที่จะทำ:

compdef _precommand start-app

และในทุบตี:

complete -F _command start-app

(คัดลอกมาจากที่หนึ่งสำหรับexecและtimeใน/usr/share/bash-completion/bash_completion)


6
แนวคิดน่ารัก +1 แต่ฉันไม่เห็นด้วยว่าเป็นความคิดที่ไม่ดีโดยทั่วไปในการเปลี่ยนเส้นทาง stderr จากแอพ GUI 99% ของผู้ใช้ทั้งหมดจะเรียกใช้จากเดสก์ท็อปกราฟิกดังนั้นพวกเขาจะไม่เห็นอะไรเลยที่ไปถึง stderr ซอฟต์แวร์ถูกออกแบบมาเพื่อรายงานข้อผิดพลาดผ่าน GUI สิ่งที่คุณเห็นใน stdout และ stderr โดยทั่วไปแล้วคือการดีบั๊กข้อความที่นักพัฒนาไม่ต้องการนำออกเพราะพวกเขาไม่คิดว่าจะมีใครเห็นพวกเขา
Ben Crowell

@ BenCrowell ฉันยอมรับว่าแอพ GUI ควรรายงานข้อผิดพลาดผ่านทาง GUI แต่ในบางกรณีอาจเกิดขึ้นได้ว่าแอปพลิเคชันล้มเหลวก่อนที่จะเริ่ม GUI สิ่งนี้เกิดขึ้นเป็นพิเศษเมื่อมีการเรียกใช้แอปพลิเคชันผ่านสคริปต์ตัวตัดคำที่แยกวิเคราะห์อาร์กิวเมนต์ (โดยทั่วไปนี่ไม่ใช่ปัญหาสำหรับผู้ใช้ที่เริ่มแอปจากเดสก์ท็อปเนื่องจากในกรณีนี้อาร์กิวเมนต์ควรถูกต้อง)
vinc17

@ BenCrowell ฉันยังนึกถึงกรณีที่$DISPLAYไม่มีการตั้งค่า (เช่นหากผู้ใช้ลืม-Xssh) หรือปัญหาการให้สิทธิ์ X เช่นที่นี่: unix.stackexchange.com/questions/108679/ …
vinc17

@ mikeserv ฉันคิดว่าผู้ใช้หลายคนอาจสนใจคำถามนี้ (ไม่ใช่แค่ OP) และพวกเขาอาจใช้ bash หรือ zsh ฉันเพิ่งเพิ่มบันทึกย่อเพื่อความสำเร็จใน zsh และ bash อย่างที่คุณเห็นนี่เป็นเรื่องง่าย
vinc17

@mikeserv โปรดทราบว่ามีการทดสอบในวันที่ เรียบง่ายและพกพาได้มากกว่า แต่มีความยืดหยุ่นน้อยลงหากต้องการเพิ่มคุณสมบัติ: "$@" 2>&1 | { quit=$(($(date +%s)+5)); while read line && [ $(date +%s) -lt $quit ]; do printf "[%s] %s\n" "$(date +%T)" "$line"; done; } | head -n 10 &(สิ่งที่สำคัญที่สุดคือความคิดไม่ใช่การนำไปใช้จริง)
vinc17

5

คำตอบนี้มีไว้สำหรับทุบตี ตัวอย่างเช่นนี่คือสิ่งที่ฉันทำใน. bashrc ของฉันเพื่อทำให้คำสั่งอำนวยความสะดวกevในการเริ่มต้นโปรแกรมดู PDF Evince

ev() { (evince "$1" 1>/dev/null 2>/dev/null &) }
complete -f -o default -X '!*.pdf' ev

evบรรทัดแรกกำหนดฟังก์ชั่น ชื่อของฟังก์ชั่นจะรับรู้เมื่อคุณใช้มันในบรรทัดคำสั่งดังนี้:

ev foo.pdf

(นี่เป็นกลไกที่แตกต่างจากนามแฝงและมีลำดับความสำคัญต่ำกว่า) Evince ส่งออกไปยัง stdin และ stdout จะถูกส่งไปยัง bitbucket (/ dev / null) เครื่องหมายและวางงานในพื้นหลัง การล้อมรอบคำสั่งในวงเล็บทำให้คำสั่งถูกรันในเชลล์ย่อยเพื่อที่จะไม่พิมพ์ข้อความเกี่ยวกับการสร้างงานพื้นหลังหรือความสมบูรณ์

บรรทัดที่สองจาก. bashrc ของฉันใช้ฟังก์ชั่นที่สมบูรณ์ของ bash เพื่อบอก bash ว่าอาร์กิวเมนต์ของคำสั่ง ev นั้นคาดว่าจะเป็นไฟล์ที่มีนามสกุลไฟล์ pdf ซึ่งหมายความว่าหากฉันมีไฟล์ foo.tex, foo.aux ฯลฯ อยู่ในไดเรกทอรีของฉันฉันสามารถพิมพ์ev fooและกดปุ่มแท็บและทุบตีจะรู้ว่าเติมชื่อไฟล์เป็น foo.pdf


1
เบ็นแค่นั้นคุณก็รู้ว่าคุณอาจจะฟังก์ชั่นการหักโหมเกินไป ไม่มีการกระทำผิดกฎหมาย - เป็นคำตอบที่ดีและฉันเป็นคนแรกที่ตอบคำถาม & ... แต่ให้พิจารณาev() (evince "$@" >&2 &) 2>/dev/null
mikeserv

หรือev() (evince "$@" &>/dev/null $)
เกล็นแจ็

@glenn: &ผมเชื่อว่าคุณหมายสำหรับตัวสุดท้ายในคำแนะนำของคุณจะเป็น
G-Man กล่าวว่า 'Reinstate Monica'

ใช่ถูกต้องแล้ว
เกล็นแจ็

5

ความเป็นไปได้อีกอย่างหนึ่งก็คือใช้commandลดระดับexecจากบิวด์อินพิเศษไปเป็นบิวด์อินธรรมดาอย่าง:

alias shh='command exec >/dev/null 2>&1'

ดังนั้นตอนนี้คุณสามารถทำได้:

(shh; call some process &)

ฉันเพิ่งสังเกตเห็นcommandว่าไม่ได้ทำงานในzsh (ดูเหมือนว่าจะทำในเปลือกหอยส่วนใหญ่อื่น ๆ )แต่ที่มันไม่ทำงานคุณสามารถทำได้แทน:

alias shh='eval "exec >/dev/null 2>&1"'

... ซึ่งควรทำงานได้ทุกที่

ในความเป็นจริงคุณอาจทำ:

alias shh='command exec >"${O:-/dev/null}" 2>&1'

ดังนั้นคุณสามารถทำได้:

O=./logfile; (shh;echo can anyone hear &)
O=; (shh; echo this\? &)
cat ./logfile

เอาท์พุท

can anyone hear

การติดตามการอภิปรายแสดงความคิดเห็นกับ @ vinc17 เป็นเรื่องที่น่าสังเกตว่าเอาต์พุตคอนโซลของแอพ GUI เกือบทั้งหมดนั้นมีไว้สำหรับXคอนโซล tty เมื่อคุณเรียกใช้XแอปจากX .desktopไฟล์เอาต์พุตที่สร้างขึ้นจะถูกส่งไปยังXเทอร์มินัลเสมือนของ - ซึ่งเป็นสิ่งที่ tty ที่คุณเปิดใช้Xในตอนแรก ฉันสามารถอยู่จำนวน TTY $XDG_VTNRนี้กับ

น่าแปลกที่แม้ว่า - และอาจจะเพราะผมเพิ่งเริ่มใช้startx- /dev/tty$XDG_VTNRฉันไม่สามารถดูเหมือนจะเป็นเพียงแค่การเขียนไปยัง นี้อาจ(ตามที่ผมคิดว่ามีโอกาสมากขึ้น)มีสิ่งที่จะทำอย่างไรกับการเปลี่ยนแปลงมากที่ผ่านมาและดำเนินการด้วยความรุนแรงXorgv1.16 ที่ช่วยให้สามารถทำงานภายใต้systemdเซสชันของผู้ใช้แทนที่จะต้องรากสิทธิพิเศษ

ถึงกระนั้นฉันสามารถทำ:

alias gui='command exec >/dev/tty$((1+$XDG_VTNR)) 2>&1'

(gui; some x app &)

ตอนนี้some x appเอาท์พุทของคอนโซลทั้งหมดถูกส่งไปที่/dev/tty$((1+$XDG_VTNR))แทนที่จะxtermเป็น pty ของฉัน ฉันสามารถรับหน้าสุดท้ายของหน้านี้เมื่อใดก็ได้เช่น:

fmt </dev/vcs$((1+$XDG_VTNR))

อาจเป็นวิธีที่ดีที่สุดในการอุทิศเทอร์มินัลเสมือนบางส่วนเพื่อบันทึกเอาต์พุตต่อไป /dev/consoleโดยทั่วไปแล้วสงวนไว้สำหรับสิ่งนี้แม้ว่าคุณอาจไม่ต้องการทำสิ่งchownที่เป็นไปได้สำหรับคุณที่จะเขียนถึงสิ่งนี้ คุณอาจมีฟังก์ชั่นบางอย่างที่ช่วยให้คุณทำprintk- ซึ่งโดยทั่วไปแล้วพิมพ์ไป/dev/console- และสามารถใช้ในแบบที่ฉันคิด

อีกวิธีหนึ่งในการทำเช่นนี้ก็คือการอุทิศptyตามวัตถุประสงค์ดังกล่าว ตัวอย่างเช่นคุณสามารถxtermเปิดหน้าต่างค้างไว้บันทึกผลลัพธ์ของttyเมื่อเรียกใช้จากที่นั่นในตัวแปรสภาพแวดล้อมและใช้ค่านั้นเป็นปลายทางสำหรับguiผลลัพธ์ของ ด้วยวิธีดังกล่าวบันทึกทั้งหมดจะถูกส่งไปยังหน้าต่างบันทึกแยกต่างหากซึ่งคุณสามารถเลื่อนดูได้หากคุณต้องการ

ฉันเคยเขียนคำตอบเกี่ยวกับวิธีการทำสิ่งที่คล้ายกันกับbashประวัติศาสตร์ถ้าคุณสนใจ


1
ฉันขอแนะนำให้คุณลบคำพูดของคุณออกecho $?เพราะมันเพิ่มข้อมูลที่ไร้ประโยชน์และขึ้นอยู่กับข้อผิดพลาดในทุบตีซึ่งฉันเพิ่งรายงานที่นี่: lists.gnu.org/archive/html/bug-bash/2014- 08 / msg00081.htmlและใน Debian BTS: bugs.debian.org/cgi-bin/bugreport.cgi?bug=758969
vinc17

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