beri tahu apakah perintah terakhir kosong di PROMPT_COMMAND

12

Dalam bash, dari dalam PROMPT_COMMAND, apakah ada cara untuk mengetahui apakah pengguna cukup menekan 'kembali' dan tidak memasukkan perintah?

pengguna
sumber

Jawaban:

7

Periksa apakah nomor riwayat bertambah. Permintaan yang dibatalkan atau permintaan di mana pengguna hanya menekan Entertidak akan menambah nomor riwayat.

Nomor sejarah tersedia dalam variabel HISTCMD, tetapi ini tidak tersedia di PROMPT_COMMAND(karena apa yang Anda inginkan sebenarnya ada nomor sejarah dari perintah sebelumnya; perintah yang mengeksekusi PROMPT_COMMANDsendiri tidak memiliki nomor sejarah). Anda bisa mendapatkan nomor dari output fc.

prompt_command () {
  HISTCMD_previous=$(fc -l -1); HISTCMD_previous=${HISTCMD_previous%%$'[\t ]'*}
  if [[ -z $HISTCMD_before_last ]]; then
    # initial prompt
  elif [[ $HISTCMD_before_last = "$HISTCMD_previous" ]]; then
    # cancelled prompt
  else
    # a command was run
  fi
  HISTCMD_before_last=$HISTCMD_previous
}
PROMPT_COMMAND='prompt_command'

Perhatikan bahwa jika Anda telah mengaktifkan pemerasan duplikat dalam riwayat ( HISTCONTROL=ignoredupsatau HISTCONTROL=erasedups), ini akan keliru melaporkan perintah kosong setelah menjalankan dua perintah yang identik secara berturut-turut.

Gilles 'SANGAT berhenti menjadi jahat'
sumber
Terima kasih, Gilles. Saya melewatkan sesuatu di sini. Ini sepertinya tidak pernah berjalan, karena menempatkan 'echo hello' di baris pertama dari fungsi literal tidak berfungsi, meskipun PROMPT_COMMAND = 'echo hello' tidak. Saya pikir itu mungkin masalah HISTCMD_previous vs HISTCMD_PREVIOUS, tetapi tidak ada dadu. Saya akan terus menyodok, tapi saya berkomentar karena bash fu Anda jelas merupakan liga yang melebihi milik saya.
pengguna
@user, saya memperbaiki lebih banyak kesalahan ketik, khususnya ${HISTCMD_previous%%$'[\t ]'*}bit tidak ada $'…'dan berakhir memotong setelah `, t` atau spasi alih-alih tab atau spasi setelah, tetapi bash mencetak tab.
Gilles 'SO- stop being evil'
1
Solusi ini didasarkan pada asumsi bahwa duplikat disimpan dalam riwayat (yang OFF untuk saya). Oleh karena itu solusi ini tidak berfungsi seperti yang diharapkan untuk perintah yang diulang sementara duplikat tidak disimpan dalam sejarah.
schlimmchen
4

Ada solusi, tetapi memiliki beberapa persyaratan:

Anda perlu mengatur $HISTCONTROLuntuk menyimpan SEMUA perintah, juga duplikat dan spasi. Jadi atur:

HISTCONTROL=

Sekarang tentukan fungsi untuk memanggil sebagai $PROMPT_COMMAND:

isnewline () {
  # read the last history number
  prompt_command__isnewline__last="$prompt_command__isnewline__curr"
  # get the current history number
  prompt_command__isnewline__curr="$(history 1 | grep -oP '^\ +\K[0-9]+')"
  [ "$prompt_command__isnewline__curr" = "$prompt_command__isnewline__last" ] && \
    echo "User hit return"
}

Sekarang, atur $PROMPT_COMMANDvariabel:

PROMPT_COMMAND="isnewline"

Lihat hasilnya:

user@host:~$ true
user@host:~$ <return>
User hit return
user@host:~$ <space><return>
user@host:~$ 
kekacauan
sumber
Saya tidak mengerti mengapa Anda menggunakan file sementara di sini. Variabel lastdipertahankan dari satu permintaan isnewlineke yang berikutnya (hanya memilih nama yang kurang umum seperti prompt_command__isnewline__lastuntuk menghindari bentrokan).
Gilles 'SO- stop being evil'
@Gilles Anda benar, saya mengubahnya, terima kasih atas saran Anda
kekacauan
Terima kasih, kekacauan. Saya menggunakan ide yang sama untuk yang berikut ini, yang sedikit lebih mudah diurai. HISTCONTROL="" function last_was_blank { local last_command="$(history 1)" if [[ "$last_was_blank_PREVIOUS_LINE" = "$last_command" ]] ; then echo "true" else echo "false" fi export last_was_blank_PREVIOUS_LINE="$last_command" } PROMPT_COMMAND=last_was_blank
pengguna
1

Saya tidak tahu cara untuk melakukan itu, per se . Tetapi Anda bisa mendapatkan efek yang sama dengan menggunakan

menjebak debug some_command_or_function

Ini akan menyebabkan some_command_or_functiondipanggil kapan saja Anda menjalankan perintah. Yang sulit adalah, itu tidak akan dipanggil jika Anda baru saja menekan Enter- kecuali jika Anda memiliki PROMPT_COMMAND yang ditentukan, dalam hal ini memukul akan Entermemanggil PROMPT_COMMAND, yang, pada gilirannya, memicu jebakan.

Mungkin cara paling sederhana untuk mencapai hasil yang Anda inginkan adalah mendefinisikan fungsi perangkap debug alih-alih menggunakan PROMPT_COMMAND. Tapi saya tidak tahu, karena saya tidak tahu hasil apa yang Anda inginkan. Jika Anda ingin sesuatu terjadi ketika Anda menekan Enter, dan sesuatu yang berbeda / tambahan terjadi ketika Anda mengetik perintah, maka (AFAIK) Anda perlu menggunakan perangkap debug dan PROMPT_COMMAND. Lihat jawaban ini dan yang  ini untuk cara membuat kedua mekanisme bermain bersama dengan baik.

Scott
sumber
0

(Ini akan menjadi komentar untuk jawaban yang diterima jika saya diizinkan untuk menambahkan komentar ...) @ schlimmen, Anda dapat mengatur HISTTIMEFORMATke sesuatu seperti HISTTIMEFORMAT='%F %T 'dan kemudian menyimpan dan membandingkan history 1. Itu karena dengan menghapus setidaknya timestamp dari (terakhir mungkin) perintah terakhir berubah setiap kali --- dan dengan HISSTIMEFORMATset yang tepat, history 1akan menampilkan timestamp (tidak seperti fc), dan dengan demikian berbeda bahkan antara perintah yang diulang.

Pavel Smerk
sumber