Làm thế nào để loại bỏ những phiền toái khi khởi động GUI từ thiết bị đầu cuối?


14

Tôi thích khởi chạy các ứng dụng GUI từ cửa sổ đầu cuối hơn là sử dụng máy tính để bàn đồ họa. Một sự phiền toái thường thấy là các nhà phát triển thường không lường trước được loại sử dụng này, vì vậy ứng dụng sẽ in rất nhiều tin nhắn vô dụng, khó hiểu hoặc không chính xác thành stdout hoặc stderr. Sự lộn xộn hơn nữa trên thiết bị đầu cuối xảy ra bởi vì chạy chương trình trong nền, với một &, tạo ra các báo cáo về việc tạo và kết thúc công việc.

Giải pháp cho những vấn đề này sẽ chấp nhận đối số dòng lệnh và xử lý tự động hoàn thành là gì?

Liên quan: /programming/7131670/make-bash-alias-that-takes-parameter

Câu trả lời:


15

Chuyển hướng lỗi tiêu chuẩn ngay lập tức thành /dev/nullmột ý tưởng tồi vì nó sẽ ẩn các thông báo lỗi sớm và các lỗi có thể khó chẩn đoán. Tôi đề nghị một cái gì đó giống như start-appkịch bản zsh sau đây :

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

Chỉ cần chạy nó với: start-app your_command argument ...

Kịch bản này sẽ xuất tối đa 10 dòng tin nhắn và trong tối đa 5 giây. Tuy nhiên, xin lưu ý rằng nếu ứng dụng gặp sự cố ngay lập tức (ví dụ do lỗi phân đoạn), bạn sẽ không thấy bất kỳ thông báo lỗi nào. Tất nhiên, bạn có thể sửa đổi tập lệnh này theo nhiều cách khác nhau để làm những gì bạn muốn ...

Lưu ý: Để làm cho hoàn thành hoạt động với start-apptrong zsh, nó đủ để làm:

compdef _precommand start-app

và trong bash:

complete -F _command start-app

(được sao chép từ một cho exectimetrong /usr/share/bash-completion/bash_completion).


6
Ý tưởng dễ thương, +1. Nhưng tôi không đồng ý rằng nói chung đó là một ý tưởng tồi để chuyển hướng stderr từ một ứng dụng GUI. 99% tất cả người dùng sẽ gọi nó từ máy tính để bàn đồ họa, vì vậy họ sẽ không bao giờ thấy bất cứ điều gì đã đến stderr. Phần mềm được thiết kế để báo cáo lỗi thông qua GUI. Những gì bạn thấy trên thiết bị xuất chuẩn và thiết bị xuất chuẩn thường là các thông báo gỡ lỗi mà các nhà phát triển không muốn lấy ra vì họ không nghĩ ai sẽ nhìn thấy chúng.
Ben Crowell

@BenCrowell Tôi đồng ý rằng các ứng dụng GUI sẽ báo cáo lỗi thông qua GUI, nhưng trong một số trường hợp, ứng dụng có thể xảy ra lỗi trước khi khởi động GUI. Điều này đặc biệt xảy ra khi ứng dụng được gọi thông qua tập lệnh bao bọc để phân tích cú pháp các đối số (nói chung, đây không phải là vấn đề đối với người dùng khởi động ứng dụng từ máy tính để bàn vì trong trường hợp này, các đối số phải chính xác).
vinc17

@BenCrowell Tôi cũng nghĩ đến trường hợp $DISPLAYkhông được đặt (ví dụ: nếu người dùng quên -Xssh) hoặc vấn đề ủy quyền X như ở đây: unix.stackexchange.com/questions/108679/,
vinc17

@mikeerv Tôi nghĩ rằng nhiều người dùng có thể quan tâm đến câu hỏi này (không chỉ OP) và họ có thể sử dụng bash hoặc zsh. Tôi vừa thêm một ghi chú để hoàn thành trong zsh và bash. Như bạn có thể thấy, điều này là đơn giản.
vinc17

@mikeerv Lưu ý rằng có một bài kiểm tra vào ngày. Đơn giản hơn và dễ mang theo hơn, nhưng kém linh hoạt hơn nếu người ta muốn thêm các tính năng: "$@" 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 &(điểm quan trọng nhất là ý tưởng, không phải là triển khai thực tế).
vinc17

5

Câu trả lời này là dành cho bash. Ví dụ, đây là những gì tôi làm trong .bashrc của mình để tạo một lệnh thuận tiện evđể khởi động trình xem PDF Evince.

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

Dòng đầu tiên xác định một chức năng ev. Tên của một hàm sẽ được nhận ra khi bạn sử dụng nó trên dòng lệnh như thế này:

ev foo.pdf

(Đây là một cơ chế khác với bí danh và có mức độ ưu tiên thấp hơn.) Đầu ra của Evince cho stdin và stdout được gửi đến bitbucket (/ dev / null). Ampersand đặt công việc trong nền. Xung quanh lệnh trong ngoặc đơn làm cho nó được chạy trong một lớp con để nó không in các thông báo về việc tạo công việc nền hoặc hoàn thành công việc.

Dòng thứ hai từ .bashrc của tôi sử dụng hàm hoàn chỉnh của bash để báo cho bash rằng đối số của lệnh ev dự kiến ​​sẽ là một tệp có phần mở rộng pdf. Điều này có nghĩa là nếu tôi cũng có các tệp foo.tex, foo.aux, v.v., ngồi trong thư mục của mình, tôi có thể nhập ev foovà nhấn phím tab và bash sẽ biết để hoàn thành tên tệp là foo.pdf.


1
Ben, chỉ để bạn biết, bạn có thể làm quá chức năng một chút. Không có ý xúc phạm - đó là một câu trả lời tuyệt vời và tôi là người đầu tiên nâng cao q & a, nhưng ... hãy xem xétev() (evince "$@" >&2 &) 2>/dev/null
mikeerv

Hoặcev() (evince "$@" &>/dev/null $)
glenn jackman

@glenn: Tôi tin rằng bạn có nghĩa là nhân vật áp chót trong đề nghị của bạn là a &.
G-Man nói 'Phục hồi Monica'

Vâng, hoàn toàn đúng.
glenn jackman

5

Một khả năng khác là sử dụng commandđể hạ cấp exectừ một nội dung đặc biệt sang một nội dung cũ đơn giản như:

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

Vì vậy, bây giờ bạn có thể làm:

(shh; call some process &)

Tôi chỉ nhận thấy rằng commandnó không hoạt động zsh (vì nó dường như làm trong hầu hết các shell khác) , nhưng thay vào đó, nó không hoạt động mà bạn có thể làm:

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

... Mà nên làm việc ở mọi nơi.

Trong thực tế, bạn thậm chí có thể làm:

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

Vì vậy, bạn có thể làm:

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

ĐẦU RA

can anyone hear

Theo dõi một cuộc thảo luận với @ vinc17, điều đáng chú ý là hầu như tất cả đầu ra giao diện điều khiển của ứng dụng GUI thường dành cho Xtty - bảng điều khiển của nó. Khi bạn chạy một Xứng dụng từ một X .desktoptệp, đầu ra mà nó tạo ra được định tuyến đến Xthiết bị đầu cuối ảo - đó là bất cứ thứ gì mà nó được khởi chạy Xở nơi đầu tiên. Tôi có thể giải quyết số tty này với $XDG_VTNR.

Kỳ lạ thay - và có lẽ bởi vì tôi mới bắt đầu sử dụng startx- tôi dường như không còn có thể viết thư /dev/tty$XDG_VTNR. Điều này cũng có thể (như tôi nghĩ là có khả năng hơn) có liên quan đến sự thay đổi rất gần đây và quyết liệt được thực hiện với Xorgv1.16 cho phép nó chạy dưới systemdphiên người dùng thay vì yêu cầu quyền root .

Tuy nhiên, tôi có thể làm:

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

(gui; some x app &)

Bây giờ tất cả some x appđầu ra giao diện điều khiển đang được định tuyến /dev/tty$((1+$XDG_VTNR))thay vì xtermpty của tôi . Tôi có thể lấy trang cuối cùng này bất cứ lúc nào như:

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

Có lẽ cách tốt nhất là dành một số thiết bị đầu cuối ảo để ghi nhật ký đầu ra. /dev/consolethường được dành riêng cho việc này, mặc dù bạn có thể không muốn làm điều chownđó có thể được yêu cầu để bạn hoàn toàn viết thư cho điều đó. Bạn có thể có một số chức năng cho phép bạn thực hiện printk- về cơ bản là in /dev/console- và vì vậy tôi có thể sử dụng nó theo cách tôi cho là.

Một cách khác để làm điều này sẽ là dành một pty cho các mục đích như vậy. Ví dụ, bạn có thể giữ một xtermcửa sổ mở, lưu đầu ra ttykhi chạy từ đó trong một biến môi trường và sử dụng giá trị đó làm đích cho guiđầu ra của. Theo cách đó, tất cả các bản ghi sẽ được chuyển đến một cửa sổ nhật ký riêng, sau đó bạn có thể cuộn qua nếu bạn thích.

Tôi đã từng viết một câu trả lời về cách một điều tương tự có thể được thực hiện với bashlịch sử, nếu bạn quan tâm.


1
Tôi khuyên bạn nên xóa nhận xét của mình về đầu ra echo $?vì nó bổ sung thông tin vô ích và nó dựa trên một lỗi trong bash, mà tôi vừa báo cáo ở đây: list.gnu.org/archive/html/orms-bash/2014- 08 / Spy00081.html và trong BTS Debian: bug.debian.org/cgi-bin/orpreport.cgi?orms=758969
vinc17

@ vinc17 yup - tôi đoán tôi phải làm điều đó trong bash thật kỳ lạ - bởi vì tôi không bao giờ sử dụng cái vỏ đó. đoán tôi chỉ cho câu trả lời này.
mikeerv
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.