Tekan tombol apa saja untuk menjeda skrip shell, tekan lagi untuk melanjutkan


10

Saya telah menulis skrip shell untuk menguji API yang menyalin file dan menggemakan progresnya setelah masing-masing.

Ada tidur dua detik di antara setiap salinan, jadi saya ingin menambahkan kemampuan untuk menekan tombol apa saja untuk menjeda skrip untuk memungkinkan pengujian yang lebih dalam. Kemudian tekan tombol apa saja untuk melanjutkan.

Bagaimana saya bisa menambahkan ini dalam beberapa baris mungkin?

Jawaban:


12

Anda tidak perlu menambahkan sesuatu ke skrip Anda. Shell memungkinkan fungsi seperti itu.

  • Mulai skrip Anda di terminal.
  • Saat sedang berjalan dan memblokir penggunaan terminal ctrl- z. Terminal dilepaskan lagi dan Anda melihat pesan bahwa proses dihentikan. (Sekarang dalam kondisi porcess T, berhenti)
  • Sekarang lakukan apapun yang kamu mau. Anda juga dapat memulai proses / skrip lain dan menghentikannya dengan ctrl- z.
  • Ketik jobsterminal atau daftar semua pekerjaan yang dihentikan.
  • Untuk membiarkan skrip Anda berlanjut, ketik fg(foreground). Ini melanjutkan pekerjaan kembali ke grup proses latar depan dan pekerjaan terus berjalan.

Lihat sebuah contoh:

root@host:~$ sleep 10 # sleep for 10 seconds
^Z
[1]+  Stopped                 sleep 10
root@host:~$ jobs # list all stopped jobs
[1]+  Stopped                 sleep 10
root@host:~$ fg # continue the job
sleep 10
root@host:~$ # job has finished

seperti yang Anda katakan, jika saya menjalankan sleep 10; notify-send hellodan tekan CTRL + Z untuk berhenti, notify-send hellojalankan. jika perintah kedua dijalankan, mengapa proses pertama dihentikan? setelah itu jika ketik fgsaya tidak bisa melihat sesuatu terjadi, yang jelas, karena perintah kedua sudah dijalankan
Edward Torvalds

@edwardtorvalds karena kedua perintah terpisah. Dalam naskah mereka harus dalam subkulit. Tuliskan dalam skrip sederhana dan jalankan skripnya. Kemudian ctrl-z untuk berhenti dan Anda akan melihat perintah kedua tidak dijalankan sampai yang pertama selesai. Menulis cmd; cmd; cmd;itu seperti menulis cmd <newline> cmd <newline> .... Atau untuk skrip yang dapat Anda tulis ( cmd; cmd; cmd; ), itu akan berperilaku seperti skrip, karena subkulit yang dihasilkan oleh(
chaos

saya juga mencoba sleep 10. ketika saya menekan CTRL + Z setelah 3 detik dan kembali setelah beberapa detik dan memperhatikan bahwa perintah tidur mati dalam waktu kurang dari 7 detik. yang berlawanan dengan apa yang Anda katakan, karena perintah nevers akan berhenti hanya berjalan di latar belakang.
Edward Torvalds

@edwardtorvalds saya perhatikan itu juga ... Tidak masuk akal. Saya straced sleepperintah dan menemukan bahwa panggilan sistem yang digunakan adalah nanosleep(). Tampaknya menjadi tindakan khusus dari panggilan nanosleepsistem. restart_syscall()memulai ulang panggilan sistem yang terputus dengan argumen waktu yang disesuaikan untuk memperhitungkan waktu yang telah berlalu (termasuk waktu di mana proses dihentikan oleh sinyal). Baca halaman manual itu: man7.org/linux/man-pages/man2/restart_syscall.2.html
chaos

Beberapa catatan untuk menyelesaikan jawaban @chaos (jangan ragu untuk memasukkannya ke dalam): ketika seseorang melakukan ctrl-Z, pekerjaan tersebut ditangguhkan ("dihentikan"), sehingga tidak berjalan saat ini, menunggu Anda memutuskan untuk melanjutkannya di latar depan (ex:) fg %1atau latar belakang (ex:) bg %1. (jika pekerjaan hanya memberikan 1 angka, yaitu hanya 1 proses yang ditangguhkan, seperti yang ditunjukkan dalam contoh kekacauan: hanya [1]+ stopped sleep 10, Anda dapat menghilangkan %nbagian tersebut. jika ada beberapa proses latar belakang (berjalan atau berhenti), Anda perlu menetapkan yang Anda inginkan dengan: %n(mis: fg %2 memiliki% 2 resume di latar depan))
Olivier Dulac

6

Jika Anda hanya ingin menjeda skrip sementara tetap berada di dalam skrip maka Anda dapat menggunakan baca alih-alih tidur.

Kamu bisa menggunakan

read -tuntuk mengatur batas waktu untuk membaca
read -nuntuk membaca satu karakter (secara efektif cukup tekan tombol apa saja) untuk melanjutkan skrip

Karena Anda belum memberikan kode apa pun, di bawah ini adalah contoh bagaimana kode itu dapat digunakan.
Jika q ditekan maka read -n1mencegah skrip dari melanjutkan sampai tombol ditekan.
Ketika suatu tombol ditekan maka centang diatur ulang dan skrip berlanjut dalam loop seperti biasa.

while [[ true ]]; do
    read -t2 -n1 check
    if [[ $check == "q" ]];then
        echo "pressed"
        read -n1
        check=""
    else
        echo "not pressed"
    fi
echo "Doing Something"
done

Anda juga dapat menambahkan stty -echobagian awal dan stty echoakhir untuk mencegah pengetikan mengacaukan hasil layar


@ mikeserv Saya tidak berpikir op peduli dengan apa yang dibaca, mereka hanya ingin menghentikan sementara dan melanjutkan skrip, apa yang Anda maksud dengan menyimpan pengaturan terminal juga, saya hanya mengubah satu sehingga sepertinya sedikit berlebihan.

1
@ mikeserv ahh benar, saya hanya menduga bahwa semua stdin akan datang dari pengguna.

1

Dengan ddAnda dapat dengan andal membaca satu byte dari file. Dengan sttyAnda dapat mengatur minsejumlah byte untuk memenuhi syarat terminal baca dan timekeluar dalam sepersepuluh detik. Kombinasikan keduanya dan Anda dapat melakukannya tanpa sleepsepenuhnya, saya pikir, dan biarkan batas waktu terminal baca bekerja untuk Anda:

s=$(stty -g </dev/tty)
(while stty raw -echo isig time 20 min 0;test -z "$(
dd bs=1 count=1 2>/dev/null; stty "$s")" || (exec sh)
do echo "$SECONDS:" do your stuff here maybe                             
   echo  no sleep necessary, I think                                                          
   [ "$((i+=1))" -gt 10 ] && exit                                                             
done       
) </dev/tty

Itu adalah contoh kecil whileloop yang saya coba-coba untuk Anda coba. Setiap dua detik ddkeluar dari percobaan membaca stdin- diarahkan dari /dev/tty- dan whileloop loop. Itu atau dd tidak time-out karena Anda menekan tombol - dalam hal ini shell interaktif dipanggil.

Berikut ini adalah uji coba - angka yang dicetak di kepala setiap baris adalah nilai dari variabel shell $SECONDS:

273315: do your stuff here maybe
no sleep necessary, I think
273317: do your stuff here maybe
no sleep necessary, I think
273319: do your stuff here maybe
no sleep necessary, I think
273321: do your stuff here maybe
no sleep necessary, I think
sh-4.3$ : if you press a key you get an interactive shell
sh-4.3$ : this example loop quits after ten iterations
sh-4.3$ : or if this shell exits with a non-zero exit status
sh-4.3$ : and speaking of which, to do so you just...
sh-4.3$ exit
exit
273385: do your stuff here maybe
no sleep necessary, I think
273387: do your stuff here maybe
no sleep necessary, I think
273389: do your stuff here maybe
no sleep necessary, I think
273391: do your stuff here maybe
no sleep necessary, I think
273393: do your stuff here maybe
no sleep necessary, I think
273395: do your stuff here maybe
no sleep necessary, I think
273397: do your stuff here maybe
no sleep necessary, I think

Jika Anda tidak menggunakan stty sanesetelah mengubah pengaturan stty, saya mungkin salah tetapi sepertinya Anda tidak meresetnya di mana saja?

@Jidder - tidak, saya menyimpan status terminal di bagian atas skrip dengan s=$(stty -g </dev/tty). Segera setelah menelepon ddsaya kemudian mengembalikannya dengan stty "$s". Status terminal tidak peduli dengan subshell dan pengaturan itu tetap terlepas dari shell induknya. stty sanebelum tentu apa yang ingin Anda lakukan - lebih baik mengembalikan negara ke cara Anda menemukannya daripada menganggap negara sanepada saat itu. Jika saya tidak mengembalikannya, semua itu ada echodi mana-mana. Mengetahui hal itu adalah sebagian alasan mengapa saya datang sangat terlambat - jawaban Anda tidak ada di sini ketika saya mulai menguji.
mikeserv
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.