Bagaimana cara menghilangkan gangguan ketika memulai GUI dari terminal?

14

Saya lebih suka meluncurkan aplikasi GUI dari jendela terminal daripada dengan menggunakan desktop grafis. Yang sering membuat jengkel adalah sering pengembang tidak mengantisipasi jenis penggunaan ini, sehingga aplikasi mencetak banyak pesan yang tidak berguna, samar, atau tidak informatif ke stdout atau stderr. Kekacauan lebih lanjut pada terminal terjadi karena menjalankan program di latar belakang, dengan &, menghasilkan laporan penciptaan dan penghentian pekerjaan.

Apa solusi untuk masalah ini yang akan menerima argumen baris perintah dan menangani pelengkapan otomatis?

Terkait: /programming/7131670/make-bash-alias-that-takes-parameter

Ben Crowell
sumber

Jawaban:

15

Mengarahkan kesalahan standar segera ke /dev/nulladalah ide yang buruk karena akan menyembunyikan pesan kesalahan awal, dan kegagalan mungkin sulit untuk didiagnosis. Saya menyarankan sesuatu seperti start-appskrip zsh berikut :

#!/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 &

Jalankan saja dengan: start-app your_command argument ...

Skrip ini akan menampilkan paling banyak 10 baris pesan dan paling lama 5 detik. Namun perhatikan bahwa jika aplikasi crash segera (misalnya karena kesalahan segmentasi), Anda tidak akan melihat pesan kesalahan. Tentu saja, Anda dapat memodifikasi skrip ini dengan berbagai cara untuk melakukan apa yang Anda inginkan ...

Catatan: Agar penyelesaian berfungsi dengan baik start-appdi zsh, cukup untuk melakukan:

compdef _precommand start-app

dan dalam bash:

complete -F _command start-app

(disalin dari yang untuk execdan timedi /usr/share/bash-completion/bash_completion).

vinc17
sumber
6
Gagasan lucu, +1. Tapi saya tidak setuju bahwa itu adalah ide yang buruk secara umum untuk mengarahkan stderr dari aplikasi GUI. 99% dari semua pengguna akan memintanya dari desktop grafis, sehingga mereka tidak akan pernah melihat apa pun yang masuk ke stderr. Perangkat lunak ini dirancang untuk melaporkan kesalahan melalui GUI. Apa yang Anda lihat di stdout dan stderr biasanya men-debug pesan yang tidak perlu diambil pengembang karena mereka tidak berpikir ada orang yang akan melihatnya.
Ben Crowell
@ BenCrowell Saya setuju bahwa aplikasi GUI harus melaporkan kesalahan melalui GUI, tetapi dalam beberapa kasus, mungkin terjadi bahwa aplikasi gagal sebelum memulai GUI. Ini terjadi khususnya ketika aplikasi dipanggil melalui skrip wrapper yang mem-parsing argumen (secara umum, ini bukan masalah bagi pengguna yang memulai aplikasi dari desktop karena dalam kasus ini, argumen harus benar).
vinc17
@ BenCrowell Saya juga memikirkan kasus di mana $DISPLAYtidak diatur (misalnya jika pengguna lupa -Xuntuk ssh) atau masalah otorisasi X seperti di sini: unix.stackexchange.com/questions/108679/…
vinc17
@ mikeserv Saya pikir berbagai pengguna mungkin tertarik pada pertanyaan ini (bukan hanya OP), dan mereka dapat menggunakan bash atau zsh. Saya baru saja menambahkan catatan untuk penyelesaian dalam zsh dan bash. Seperti yang Anda lihat, ini sederhana.
vinc17
@ mikeserv Perhatikan bahwa ada tes pada tanggal tersebut. Lebih sederhana dan lebih portabel, tetapi kurang fleksibel jika seseorang ingin menambahkan fitur: "$@" 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 &(poin yang paling penting adalah idenya, bukan implementasi yang sebenarnya).
vinc17
5

Jawaban ini untuk bash. Sebagai contoh, inilah yang saya lakukan di .bashrc saya untuk membuat perintah kenyamanan evuntuk memulai penampil PDF Evince.

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

Baris pertama mendefinisikan suatu fungsi ev. Nama fungsi akan dikenali saat Anda menggunakannya di baris perintah seperti ini:

ev foo.pdf

(Ini adalah mekanisme yang berbeda dari alias, dan memiliki prioritas lebih rendah.) Output Evince ke stdin dan stdout dikirim ke bitbucket (/ dev / null). Ampersand menempatkan pekerjaan di latar belakang. Mengurung perintah dalam tanda kurung menyebabkannya dijalankan dalam subkulit sehingga tidak mencetak pesan tentang penciptaan pekerjaan latar belakang atau penyelesaiannya.

Baris kedua dari .bashrc saya menggunakan fungsi lengkap bash untuk memberi tahu bash bahwa argumen dari perintah ev diharapkan menjadi file dengan ekstensi pdf. Ini berarti bahwa jika saya juga memiliki file foo.tex, foo.aux, dll., Duduk di direktori saya, saya dapat mengetik ev foodan menekan tombol tab, dan bash akan tahu untuk melengkapi nama file sebagai foo.pdf.

Ben Crowell
sumber
1
Ben, asal tahu saja, Anda mungkin sedikit berlebihan fungsinya. Bukan pelanggaran berarti - ini adalah jawaban yang bagus dan saya adalah orang pertama yang menjawab q & a, tapi ... pertimbangkanev() (evince "$@" >&2 &) 2>/dev/null
mikeserv
Atauev() (evince "$@" &>/dev/null $)
glenn jackman
@glenn: Saya percaya bahwa Anda bermaksud untuk karakter kedua dari belakang dalam saran Anda untuk menjadi &.
G-Man Mengatakan 'Reinstate Monica'
Ya benar.
glenn jackman
5

Kemungkinan lain adalah menggunakan commanduntuk menurunkan execdari builtin khusus ke builtin lama polos seperti:

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

Jadi sekarang Anda bisa melakukannya:

(shh; call some process &)

Saya baru saja memperhatikan bahwa commandtidak berfungsizsh (seperti yang terlihat di kebanyakan shell lain) , tetapi jika tidak berhasil, Anda dapat melakukannya:

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

... yang seharusnya bekerja di mana-mana.

Bahkan, Anda mungkin melakukannya:

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

Jadi Anda bisa melakukan:

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

KELUARAN

can anyone hear

Menindaklanjuti diskusi komentar dengan @ vinc17, perlu dicatat bahwa hampir semua output konsol aplikasi GUI umumnya ditujukan untuk Xtty - konsolnya. Ketika Anda menjalankan Xaplikasi dari suatu X .desktopfile, output yang dihasilkannya dialihkan ke Xterminal virtual - yang merupakan tty dari mana Anda meluncurkannya.X . Saya dapat membahas nomor tty ini dengan $XDG_VTNR.

Anehnya - dan mungkin karena saya baru saja mulai menggunakan startx- saya tidak lagi bisa menulis /dev/tty$XDG_VTNR. Ini mungkin juga (karena saya pikir lebih mungkin) ada hubungannya dengan perubahan yang sangat baru dan drastis diimplementasikan dengan Xorgv1.16 yang memungkinkannya berjalan di bawah systemdsesi pengguna daripada membutuhkan hak akses root .

Meski begitu, saya bisa melakukan:

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

(gui; some x app &)

Sekarang semua some x app's konsol keluaran sedang diarahkan ke /dev/tty$((1+$XDG_VTNR))daripada saya xterm' s pty. Saya bisa mendapatkan halaman terakhir ini kapan saja seperti:

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

Ini mungkin praktik terbaik untuk mendedikasikan beberapa terminal virtual untuk mencatat keluaran. /dev/consoleumumnya sudah dicadangkan untuk ini, meskipun Anda mungkin lebih suka untuk tidak melakukan hal chownyang mungkin diperlukan bagi Anda untuk menulis itu. Anda mungkin memiliki beberapa fungsi yang memungkinkan Anda melakukan aprintk - yang pada dasarnya mencetak/dev/console - dan bisa menggunakannya dengan cara yang saya kira.

Cara lain untuk melakukan hal ini akan mendedikasikan pty untuk tujuan tersebut. Anda dapat, misalnya, xtermmembuka jendela, menyimpan outputtty ketika dijalankan dari sana dalam variabel lingkungan, dan menggunakan nilai itu sebagai tujuan untukgui output. Dengan cara itu semua log akan dialihkan ke jendela log yang terpisah, yang kemudian bisa Anda gulir jika Anda suka.

Saya pernah menulis jawaban tentang bagaimana hal serupa dapat dilakukan dengan bashsejarah, jika Anda tertarik.

mikeserv
sumber
1
Saya menyarankan Anda menghapus komentar Anda pada output echo $?karena menambahkan informasi yang tidak berguna dan didasarkan pada bug di bash, yang baru saja saya laporkan di sini: lists.gnu.org/archive/html/bug-bash/2014- 08 / msg00081.html dan di BTS Debian: bugs.debian.org/cgi-bin/bugreport.cgi?bug=758969
vinc17
@ vinc17 yup - saya kira saya harus melakukan itu di bash yang aneh - karena saya tidak pernah menggunakan shell itu. kira saya hanya untuk jawaban ini.
mikeserv