Thông báo trên màn hình khi hoàn thành các lệnh chạy dài


59

Tôi muốn có một thông báo trên màn hình bất cứ khi nào một lệnh chạy hơn 15 giây, kết thúc trong một vỏ tương tác.

Nói cách khác, tôi muốn tất cả các lệnh được gói trong một cái gì đó như thế này

start=$(date +%s);
ORIGINAL_COMMAND;
[ $(($(date +%s) - start)) -le 15 ] || notify-send "Long running command finished"

Cách tốt nhất để thực hiện điều này trong bash là gì?


1
Có thể giống nhau trên Superuser: superuser.com/questions/31917/ Hãy
Ciro Santilli 心 心


Tại sao bạn lại thêm "trong vỏ tương tác" ngay bây giờ? Nó có thể làm mất hiệu lực một số câu trả lời hiện có trong ngữ cảnh của bài đăng gốc của bạn trong hơn một năm. Nếu bạn cần một giải pháp dành riêng cho shell tương tác, hãy xem xét đặt câu hỏi riêng tham khảo câu hỏi này.
Sergiy Kolodyazhnyy

Phần "vỏ tương tác" đã được làm rõ trong bình luận đầu tiên trước khi chỉnh sửa. Tôi chỉ đơn giản là chỉnh sửa câu hỏi và xóa bình luận. Bên cạnh đó, 3 dòng được đăng trong các câu hỏi hoạt động tốt cho một kịch bản.
aioobe

Câu trả lời:


24

Bạn muốn https://launchpad.net/undistract-me (có thể cài đặt từ kho lưu trữ Ubuntu với sudo apt-get install undistract-me) chính xác những gì bạn yêu cầu, bao gồm làm việc tự động (nghĩa là, không cần phải nhớ thêm một thứ gì đó vào tiềm năng lâu dài lệnh chạy).


1
Nó dường như không hoạt động. Tôi đã cài đặt nó, khởi động lại hệ thống của mình và thử nghiệm sleep 30nhưng không có thông báo.
Galgalesh

4
Bạn cần thêm hai dòng sau vào .bashrc: . /usr/share/undistract-me/long-running.bash notify_when_long_running_commands_finish_install. Nó dường như là một lỗi: github.com/jml/undistract-me/issues/23
Ludenticus

32

Theo như tôi hiểu bạn muốn có một cái bọc . Và bạn muốn sử dụng một lệnh thông qua nó để nó sẽ cung cấp cho bạn thông báo mong muốn nếu thời gian chạy lệnh của bạn dài hơn 15 giây. Vì vậy, đây là nó.

wrapper(){
    start=$(date +%s)
    "$@"
    [ $(($(date +%s) - start)) -le 15 ] || notify-send "Notification" "Long\
 running command \"$(echo $@)\" took $(($(date +%s) - start)) seconds to finish"
}

Sao chép chức năng này trong ~/.bashrcvà nguồn của bạn ~/.bashrcnhư,

. ~/.bashrc

Truyền thừa

wrapper <your_command>

Nếu mất hơn 15 giây, bạn sẽ nhận được thông báo trên màn hình mô tả lệnh và thời gian thực hiện.

Thí dụ

wrapper sudo apt-get update

ảnh chụp màn hình nitrat hóa máy tính để bàn


1
"$@", Không $@. Sự khác biệt lớn.
geirha

4
Tôi muốn tránh viết wrappertrước mỗi lệnh tôi gõ.
aioobe

2
@aioobe bạn có thể sử dụng tên hàm ngắn hơn thậm chí có thể là một chữ cái. nhưng một trình bao bọc hoạt động theo cách này.
souravc

3
command; alerttrên thực tế ngắn hơn wrapper command:-)
aioobe

1
Nếu bạn không muốn notify-sendhết hạn trong một thời gian dài thì hãy thông báo - gửi thời gian chờ tùy chỉnh (tính bằng mili giây). ví dụnotify-send --expire-time 999999999 ...
Bryce Guinta

26

Trong ~/.bashrcđó có một bí danh alertđược định nghĩa là:

alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"'

có thể được sử dụng để thông báo hoàn thành thực thi lệnh.

Sử dụng:

$ the_command; alert

ví dụ

$ sudo apt-get update; alert

snap1

Bạn có thể tùy chỉnh bí danh theo nhu cầu và mong muốn của bạn.


3
Thật tuyệt khi biết điều đó. Có cách nào để thêm cảnh báo sau mỗi lệnh tôi gõ (và cũng chỉ có cảnh báo nếu lệnh mất hơn 15 giây)?
aioobe

Điều kỳ lạ là nó đã được thêm vào .bashrc của tôi, nó có mặc định trong Ubuntu không?
Vignesh

13

Ngoài một trình bao bọc như souravc đề xuất, thực sự không có cách nào tốt để làm điều này trong bash. Bạn có thể hack theo cách của mình với bẫy DEBUG và PROMPT_COMMAND. Bẫy DEBUG được kích hoạt bất cứ khi nào bạn chạy lệnh và PROMPT_COMMAND được chạy ngay trước khi lời nhắc được viết.

Vì vậy, công cụ để ~/.bashrctrở thành một cái gì đó như

trap '_start=$SECONDS' DEBUG
PROMPT_COMMAND='(if (( SECONDS - _start > 15 )); then notify-send "Long running command ended"; fi)'

Đây là một hack, vì vậy đừng ngạc nhiên nếu bạn gặp phải tác dụng phụ kỳ lạ với điều này.


4

BIÊN TẬP

TL; DR : tạo lối tắt tự động hoàn thành trong .inputrcvà hoạt động trong .bashrc . Chạy lệnh như bình thường, nhập, nhưng thay vì ENTER, nhấn phím tắt mà bạn đã chỉ định trong.inputrc

Người đặt tiền thưởng cho câu hỏi này cho biết:

"Tất cả các câu trả lời hiện tại yêu cầu nhập một lệnh bổ sung sau lệnh. Tôi muốn một câu trả lời tự động thực hiện điều này."

Trong khi nghiên cứu các giải pháp cho vấn đề này, tôi đã vấp phải câu hỏi này từ stackexchange, cho phép liên kết CtrlJvới một chuỗi các lệnh: Ctrla(di chuyển đến đầu dòng), đặt chuỗi "mesure" trước lệnh bạn đã nhập, Ctrlm(thực thi)

Do đó, bạn có được chức năng tự động hoàn thành và ENTERlệnh riêng biệt để đo thời gian, trong khi vẫn duy trì mục đích ban đầu của chức năng thứ hai tôi đã đăng dưới đây.

Đến bây giờ, đây là nội dung của ~/.inputrctập tin của tôi :

"\C-j": "\C-a measure \C-m"

Và đây là nội dung của .bashrc(lưu ý, tôi đã không sử dụng bash mãi mãi - tôi sử dụng mksh làm vỏ của mình, do đó đó là những gì bạn thấy trong bài viết gốc. Chức năng vẫn giống nhau)

PS1=' serg@ubuntu [$(pwd)]
================================
$ '
function measure () 
{

/usr/bin/time --output="/home/xieerqi/.timefile" -f "%e" $@ 

if [ $( cat ~/.timefile| cut -d'.' -f1 ) -gt 15 ]; then

    notify-send "Hi , $@ is done !"

fi


}

Bài gốc

Đây là ý tưởng của tôi - sử dụng một chức năng trong .bashrc. Nguyên tắc cơ bản - sử dụng /usr/bin/timeđể đo thời gian cần thiết để hoàn thành lệnh và nếu quá 15 giây, hãy gửi thông báo.

function measure () 
{

if [ $( /usr/bin/time -f "%e" $@ 2>&1 >/dev/null ) -gt 15 ]; then

    notify-send "Hi , $@ is done !"

fi


}

Ở đây tôi đang chuyển hướng đầu ra /dev/nullnhưng để xem đầu ra, chuyển hướng đến tập tin cũng có thể được thực hiện.

Một cách tiếp cận tốt hơn nhiều, IMHO, là gửi đầu ra thời gian đến một số tệp trong thư mục nhà của bạn (chỉ để bạn không làm ô nhiễm hệ thống của mình bằng các khung thời gian và luôn biết phải tìm ở đâu). Đây là phiên bản thứ hai

function measure () 
{

/usr/bin/time --output=~/.timefile -f "%e" $@ 

if [ $( cat ~/.timefile | cut -d'.' -f1 ) -gt 15 ]; then

    notify-send "Hi , $@ is done !"

fi


}

Và đây là ảnh chụp màn hình của phiên bản thứ nhất và thứ hai, theo thứ tự đó

Phiên bản đầu tiên, không có đầu ra nhập mô tả hình ảnh ở đây

Phiên bản thứ hai, với đầu ra nhập mô tả hình ảnh ở đây


Nhân tiện, làm việc với các lệnh sudo, quá. Tôi đã thử nó với sudo lsofvà chủ yếu là với ping -c20 google.com.
Sergiy Kolodyazhnyy

3

Gần đây tôi đã xây dựng một công cụ phục vụ mục đích này. Nó có thể được chạy như một trình bao bọc hoặc tự động tích hợp shell. Kiểm tra nó ở đây: http://ntfy.rtfd.io

Để cài đặt nó:

sudo pip install ntfy

Để sử dụng nó như một trình bao bọc:

ntfy done sleep 3

Để nhận thông báo tự động, hãy thêm thông báo này vào .bashrchoặc .zshrc:

eval "$(ntfy shell-integration)"

1

Kịch bản của bạn hoạt động khá tốt, chỉ cần đảm bảo bạn bao gồm dòng 'shebang' ( #!/bin/bash) . Những cái khác #!/bin/bashđược đề cập ở đây , nhưng hầu hết thời gian, #!/bin/bashhoạt động tốt cho các tập lệnh bash Unix. Nó được yêu cầu bởi trình thông dịch kịch bản để nó biết loại kịch bản đó là gì.

Điều này dường như hoạt động như một kịch bản thử nghiệm:

#!/bin/bash
start=$(date +%s);
   echo Started
   sleep 20;
   echo Finished!
[ $(($(date +%s) - start)) -le 15 ] || notify-send -i dialog-warning-symbolic "Header" "Message"

Để sửa đổi tập lệnh này, hãy đặt (các) lệnh trong đó các dòng echosleepdòng.

Lưu ý với notify-send, bạn cũng có thể sử dụng -iđể chỉ định một biểu tượng :-)

Ngoài ra, hãy chắc chắn rằng nó có thể được thực thi bằng cách chạy chmod +x /PATH/TO/FILEtrên nó trước.


1

Bạn có thể sửa đổi Bash để thực hiện chức năng trình bao bọc mà bạn muốn.

Nếu bạn có xu hướng thực hiện nhiều sửa đổi như vậy cho trình vỏ tương tác của mình, bạn có thể xem xét chuyển sang một trình bao có thể hack nội tại như eshell, được xây dựng bằng Emacs elisp và có tất cả các tùy chỉnh được lưu trữ của nó:

http://www.masteringemacs.org/articles/2010/12/13/complete-guide-mastering-eshell/


-2

Bạn cũng có thể làm điều này với một câu lệnh if đơn giản như thế này

#!/bin/bash

START=$(date +%s)

TIME=$(($START+15))

ORIGINAL_COMMAND;

END=$(date +%s)

if [ $END -gt $TIME ]
then
    notify-send "Task Completed"
fi

Bạn có thể sử dụng tên biến của riêng bạn.

Tôi có thể xác nhận rằng điều này hoạt động, tôi đã thử nghiệm với một lệnh mất nhiều thời gian để hoàn thành và một lệnh không và thông báo đến cho một lệnh mất nhiều thời gian

Bạn cũng có thể làm điều này với bất kỳ lệnh nào bằng cách thay thế ORIGINAL_COMMANDbằng $@và chạy tập lệnh dưới dạng ./script command.


Tại sao câu trả lời của tôi bị hạ thấp? Tôi muốn biết tôi đã sai ở đâu trong câu trả lời
Rumesh

Tôi đã không đánh giá thấp nó, nhưng tôi sẽ nói với bạn điều gì sai với nó: Trước hết, nó yêu cầu nhập một lệnh bổ sung. Tôi đặc biệt tuyên bố trong tiền thưởng của tôi, tôi không muốn làm điều đó. Thứ hai, tại sao calc? $((2+2))là một bash dựng sẵn, không yêu cầu bất kỳ chương trình bổ sung. Thứ ba: nó không hoạt động với các lệnh có khoảng trắng. tl; dr: nó tệ hơn những câu trả lời 1 năm tuổi khác
Galgalesh

Chà ..... thời gian bắt đầu và kết thúc sẽ khác nhau, phải không? Ngay cả đối với một lệnh ngắn dài 1
giây
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.