Pemberitahuan desktop saat perintah yang berjalan lama selesai

59

Saya ingin memiliki pemberitahuan desktop setiap kali perintah yang telah berjalan lebih dari, katakanlah 15 detik, selesai dalam shell interaktif.

Dengan kata lain, saya ingin semua perintah dibungkus dengan sesuatu seperti ini

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

Apa cara terbaik untuk mencapai ini di bash?

aioobe
sumber
1
Kemungkinan sama di Superuser: superuser.com/questions/31917/…
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
Mengapa Anda menambahkan "di shell interaktif" tadi? Mungkin membatalkan beberapa jawaban yang ada yang ada dalam konteks posting asli Anda selama lebih dari setahun. Jika Anda membutuhkan solusi khusus untuk shell interaktif, pertimbangkan untuk mengajukan pertanyaan terpisah dengan referensi yang satu ini.
Sergiy Kolodyazhnyy
Bagian "shell interaktif" diklarifikasi dalam komentar pertama sebelum diedit. Saya cukup mengedit pertanyaan dan menghapus komentar. Selain itu, 3 baris yang diposting dalam pertanyaan berfungsi dengan baik untuk skrip.
aioobe

Jawaban:

24

Anda ingin https://launchpad.net/undistract-me (dapat diinstal dari arsip Ubuntu dengan sudo apt-get install undistract-me) yang melakukan persis apa yang Anda minta, termasuk bekerja secara otomatis (yaitu, tanpa harus ingat untuk menambahkan sesuatu yang ekstra untuk berpotensi lama- menjalankan perintah).

sil
sumber
1
Sepertinya tidak berfungsi. Saya menginstalnya, menyalakan kembali sistem saya dan mengujinya sleep 30, tetapi tidak ada pemberitahuan.
Galgalesh
4
Anda perlu menambahkan dua baris berikut ke .bashrc: . /usr/share/undistract-me/long-running.bash notify_when_long_running_commands_finish_install. Tampaknya menjadi bug: github.com/jml/undistract-me/issues/23
Ludenticus
32

Sejauh yang saya mengerti Anda ingin bungkusnya . Dan Anda ingin menggunakan perintah melalui itu sehingga akan memberi Anda pemberitahuan yang diinginkan jika waktu menjalankan perintah Anda lebih dari 15 detik. Jadi ini dia.

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

Salin fungsi ini di ~/.bashrcdan sumber Anda ~/.bashrcsebagai,

. ~/.bashrc

Penggunaan

wrapper <your_command>

Jika dibutuhkan lebih dari 15 detik, Anda akan mendapatkan pemberitahuan desktop yang menggambarkan perintah dan waktu eksekusi.

Contoh

wrapper sudo apt-get update

tangkapan layar desktop-nitification

souravc
sumber
1
"$@", Tidak $@. Perbedaan besar.
geirha
4
Saya ingin menghindari penulisan wrapperdi depan setiap perintah yang saya ketik.
aioobe
2
@aioobe Anda dapat menggunakan nama fungsi yang lebih pendek bahkan mungkin surat. tetapi pembungkus bekerja dengan cara ini.
souravc
3
command; alertsebenarnya lebih pendek dari wrapper command:-)
aioobe
1
Jika Anda tidak ingin notify-sendkadaluwarsa untuk waktu yang lama, maka beri tahu-kirim batas waktu khusus (dalam milidetik). misalnyanotify-send --expire-time 999999999 ...
Bryce Guinta
26

Di ~/.bashrcsana ada alias yang alertdidefinisikan sebagai:

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$//'\'')"'

yang dapat digunakan untuk memberi tahu penyelesaian eksekusi perintah.

Pemakaian:

$ the_command; alert

misalnya

$ sudo apt-get update; alert

snap1

Anda dapat menyesuaikan alias sesuai kebutuhan dan keinginan Anda.

tepat
sumber
3
Itu bagus untuk diketahui. Apakah ada cara untuk menambahkan peringatan setelah setiap perintah yang saya ketik (dan juga minta peringatan hanya jika perintah tersebut membutuhkan waktu lebih dari 15 detik)?
aioobe
anehnya sudah ditambahkan ke .bashrc saya, apakah sudah default di ubuntu?
Vignesh
13

Terlepas dari pembungkus seperti yang disarankan souravc, sebenarnya tidak ada cara yang baik untuk melakukan ini di bash. Anda dapat meretasnya dengan perangkap DEBUG dan PROMPT_COMMAND. Perangkap DEBUG dipicu setiap kali Anda menjalankan perintah, dan PROMPT_COMMAND dijalankan tepat sebelum prompt ditulis.

Jadi barang untuk ~/.bashrcmenjadi sesuatu seperti

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

Ini adalah retasan, jadi jangan heran jika Anda menemukan efek samping aneh dengan ini.

geirha
sumber
4

SUNTING

TL; DR : buat pintasan pelengkapan otomatis .inputrcdan fungsikan dalam .bashrc . Jalankan perintah seperti biasa, ketikkan, tetapi alih-alih ENTER, tekan pintasan yang Anda tentukan.inputrc

Orang yang memberi hadiah pada pertanyaan ini mengatakan:

"Semua jawaban yang ada memerlukan mengetikkan perintah tambahan setelah perintah. Saya ingin jawaban yang melakukan ini secara otomatis."

Saat meneliti solusi untuk masalah ini, saya menemukan pertanyaan ini dari stackexchange, yang memungkinkan pengikatan CtrlJke urutan perintah: Ctrla(pindah ke awal baris), tempatkan string "mesure" di depan perintah yang Anda masukkan, Ctrlm(jalankan)

Dengan demikian Anda mendapatkan fungsionalitas penyelesaian otomatis dan ENTERperintah terpisah untuk mengukur waktu, sambil mempertahankan tujuan asli dari fungsi kedua yang saya posting di bawah ini.

Sampai sekarang, berikut adalah isi ~/.inputrcfile saya :

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

Dan di sini adalah isi dari .bashrc(catatan, saya belum pernah menggunakan bash selamanya - Saya menggunakan mksh sebagai shell saya, maka itulah yang Anda lihat di posting asli. Fungsionalitasnya masih sama)

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


}

Pos Asli

Inilah ide saya - gunakan fungsi dalam .bashrc. Prinsip dasar - gunakan /usr/bin/timeuntuk mengukur waktu yang dibutuhkan untuk menyelesaikan perintah, dan jika lebih dari 15 detik, kirim pemberitahuan.

function measure () 
{

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

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

fi


}

Di sini saya mengarahkan output ke /dev/nulltetapi untuk melihat output, mengarahkan ke file juga dapat dilakukan.

Pendekatan yang jauh lebih baik, IMHO, adalah mengirim output waktu ke beberapa file di folder rumah Anda (supaya Anda tidak mencemari sistem Anda dengan timefiles, dan selalu tahu ke mana harus mencari). Ini versi kedua

function measure () 
{

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

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

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

fi


}

Dan inilah screenshot dari versi pertama dan kedua, dalam urutan itu

Versi pertama, tidak ada output masukkan deskripsi gambar di sini

Versi kedua, dengan output masukkan deskripsi gambar di sini

Sergiy Kolodyazhnyy
sumber
Omong-omong, bekerja dengan perintah sudo juga. Saya sudah mengujinya dengan sudo lsofdan sebagian besar dengan ping -c20 google.com.
Sergiy Kolodyazhnyy
3

Baru-baru ini saya membangun alat yang melayani tujuan ini. Ini dapat dijalankan sebagai pembungkus atau secara otomatis dengan integrasi shell. Lihat di sini: http://ntfy.rtfd.io

Untuk menginstalnya:

sudo pip install ntfy

Untuk menggunakannya sebagai pembungkus:

ntfy done sleep 3

Untuk mendapatkan notifikasi secara otomatis, tambahkan ini ke Anda .bashrcatau .zshrc:

eval "$(ntfy shell-integration)"
Daniel Schep
sumber
1

Script Anda berfungsi dengan baik, pastikan Anda menyertakan baris 'shebang' ( #!/bin/bash) . Yang lain #!/bin/bashdisebutkan di sini , tetapi sebagian besar waktu, #!/bin/bashberfungsi dengan baik untuk skrip bash Unix. Ini diperlukan oleh penerjemah skrip sehingga ia tahu jenis skrip apa itu.

Ini tampaknya berfungsi sebagai skrip pengujian:

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

Untuk memodifikasi skrip ini, letakkan perintah di mana echodan sleepbaris berada.

Catatan dengan notify-send, Anda dapat menggunakan -iuntuk menentukan ikon juga :-)

Juga, pastikan itu dapat dieksekusi dengan menjalankannya chmod +x /PATH/TO/FILEterlebih dahulu.

Wilf
sumber
1

Anda dapat memodifikasi Bash untuk mengimplementasikan fungsionalitas pembungkus yang Anda inginkan.

Jika Anda cenderung melakukan banyak modifikasi pada shell interaktif Anda, Anda dapat mempertimbangkan untuk beralih ke shell yang secara intrinsik dapat diretas seperti eshell, yang dibangun menggunakan elac Emacs dan memiliki semua kemampuan penyesuaian bertingkat:

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

Ryan Prior
sumber
-2

Anda juga dapat melakukan ini dengan pernyataan sederhana jika seperti ini

#!/bin/bash

START=$(date +%s)

TIME=$(($START+15))

ORIGINAL_COMMAND;

END=$(date +%s)

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

Anda dapat menggunakan nama variabel Anda sendiri.

Saya dapat mengkonfirmasi bahwa ini berfungsi, saya diuji dengan perintah yang membutuhkan waktu lama untuk menyelesaikan dan yang tidak dan pemberitahuan datang untuk yang membutuhkan waktu lama

Anda juga dapat melakukan ini dengan perintah apapun dengan mengganti ORIGINAL_COMMANDdengan $@dan menjalankan script sebagai ./script command.

Rumesh
sumber
Mengapa jawaban saya tidak dipilih? Saya ingin tahu di mana saya salah dalam jawaban
Rumesh
Saya tidak downvote, tapi saya akan memberitahu Anda apa yang salah dengan itu: Pertama-tama, itu membutuhkan mengetikkan perintah tambahan. Saya secara khusus menyatakan dalam karunia saya, saya tidak ingin melakukan itu. Kedua, mengapa calc? $((2+2))adalah bash builtin, tidak memerlukan program tambahan. Ketiga: tidak bekerja dengan perintah yang memiliki spasi. tl; dr: lebih buruk daripada jawaban lain yang berumur 1 tahun
Galgalesh
Nah ..... mulai dan waktu selesai selalu akan berbeda, kan? Bahkan untuk perintah pendek yang panjangnya 1 detik
Sergiy Kolodyazhnyy