Apa yang setara dengan ZSH dari BASH's $ PROMPT_COMMAND?


24

BASH mendukung $PROMPT_COMMANDvariabel lingkungan yang mendefinisikan perintah yang akan dieksekusi sebelum prompt interaktif tingkat pertama. Saya mencari kesetaraan ZSH itu.

Dokumentasi mengatakan bahwa ada fungsi yang precmdbisa saya definisikan untuk mencapai itu; Namun, saya tidak tahu bagaimana cara mendefinisikannya dari variabel lingkungan.

Saya telah mempertimbangkan untuk mengirimkan variabel lingkungan yang akan membuat ZSH membaca file yang berisi definisi fungsi itu, tetapi ZSH tampaknya tidak mendukung hal-hal seperti itu : ia hanya membaca file global dan kemudian file per-pengguna. Saya bisa menggantinya tetapi saya tidak bisa menambahkannya tanpa memodifikasi file, yang tidak bisa saya lakukan.

Jadi, bagaimana saya mendefinisikan kait pre-prompt di ZSH melalui variabel lingkungan, seperti yang saya lakukan menggunakan $PROMPT_COMMANDdi BASH?


Sejujurnya, saya perlu kait pasca-eksekusi-perintah-eksekusi, tetapi tidak ada shell yang menyediakan jadi saya harus menggunakan kait pre-prompt - mereka tampaknya sedekat yang saya bisa dapatkan.
Shnatsel

1
Hm, saya bertanya-tanya, apa perbedaan antara eksekusi-perintah-eksekusi dan pre-prompt . Terlepas dari perbedaan konseptual, di mana Anda amati sebenarnya perbedaan. (Mari kita hilangkan perintah exitdan exec, ok ;))
mpy

@ mpy ada perbedaan ketika menjalankan pekerjaan latar belakang, karena pekerjaan latar belakang independen dari urutan yang cepat.
Shnatsel

1
Ok, saya mengerti. Jadi, bagaimana dengan sesuatu seperti itu: start() { eval "$@"; echo post-command-code }dan kemudian gunakan zle-binding untuk mengeksekusi baris perintah dengan startprepended?
mpy

1
The DEBUGperangkap adalah nice menemukan, tetapi Anda masih memiliki masalah bagaimana mendefinisikannya. Saya telah memperpanjang jawaban saya sekali lagi, tetapi saya menyerahkan kepada Anda untuk menuliskan jawaban Anda sendiri mengenai solusi perangkap DEBUG. :)
mpy

Jawaban:


24

Pendekatan paling sederhana untuk meniru bash $PROMPT_COMMANDyang muncul di pikiran saya adalah menggunakan precmdhook, seperti yang sudah Anda ketahui. Tentukan sebagai

precmd() { eval "$PROMPT_COMMAND" }

dan Anda dapat melakukan sesuatu seperti itu:

$ PROMPT_COMMAND='echo Hello, it is now $(date)'
Hello, it is now Mon, Mar 31, 2014 7:08:00 PM
$ whoami      
user
Hello, it is now Mon, Mar 31, 2014 7:08:21 PM     
$

Harap perhatikan tanda kutip tunggal dalam contoh itu, jika tidak $(date)akan diperluas terlalu dini, yaitu sudah ketika mendefinisikan $PROMPT_COMMANDdan tidak ketika dipanggil sebelum prompt.


Jika Anda ingin mempertahankan (dan tidak ingin mengubah) definisi yang ada, Anda dapat menggunakan pendekatan itu:

$ prmptcmd() { eval "$PROMPT_COMMAND" }
$ precmd_functions=(prmptcmd)

Dengan itu prmptcmdfungsi dieksekusi setelah precmd()fungsi yang ada .


Akhirnya, berikut adalah cara yang cocok untuk digunakan dalam paket program, yang tidak boleh memodifikasi file pengguna atau sistem atau memasukkan perintah interaktif.

Contoh untuk menelurkan sesi bash bisa jadi

PROMPT_COMMAND="echo foo" bash

Untuk menelurkan zsh bisa Anda gunakan

ZDOTDIR=/program/dir zsh

yang menyebabkan /program/dir/.zshrcbersumber. Dalam file ini, precmd()pengait dapat didefinisikan seperti dijelaskan di atas. Jika Anda ingin pengaturan pengguna selain sertakan source $HOME/.zshrcdll di .zshrc program, juga. Pengaturan ini dapat dipertahankan, karena tidak ada file di luar direktori program yang dimodifikasi.


Sebagai tambahan terakhir, berikut ini adalah bukti konsep bagaimana membuat pengguna baru tetap selamat datang juga. Gunakan kode berikut dalam /program/dir/.zshenvfile konfigurasi rc Anda :

echo define precmd, traps, etc.

autoload -Uz zsh-newuser-install

if [[ ! -e "$HOME/.zshrc" ]]; then
  zsh-newuser-install -f
  mv $ZDOTDIR/.zshrc $HOME/.zshrc
else
  builtin source $HOME/.zshrc
fi

Itu yang saya pikir. Masalahnya adalah - bagaimana cara saya mendefinisikan kait precmd melalui variabel lingkungan? Apakah ada mekanisme untuk menambahkan kait atau kode tanpa mengubah file? Atau bagaimana cara melakukannya setidaknya tanpa menulis ke file ".zprofile" global dan pengguna-global dan yang serupa? Seperti, dapatkah saya menambahkan .zprofile saya sendiri yang tidak akan menggantikan yang sudah ada?
Shnatsel

1
Anda juga menggunakan kait precmd di sini akan menggantikan semua kait precmd yang sudah ada; zsh docs menyebutkan saya dapat membuat array fungsi yang akan hidup berdampingan tetapi saya tidak tahu bagaimana melakukannya.
Shnatsel

1
(1) Apa yang Anda maksud dengan bagaimana cara mendefinisikan kait precmd melalui variabel lingkungan? Contoh yang saya sajikan bekerja IMHO seperti mekanisme bash. (2) Anda dapat menambahkan hook melalui baris perintah, tetapi tidak permanen. Apa masalah dengan modifikasi Anda .zshrc? (3) Contoh: foo() { echo foo }; bar() { echo bar }; precmd_functions=(foo bar)ini mengeksekusi foo()dan bar() di samping untuk precmd().
mpy

2
Ok, itu banyak menjelaskan - contoh minimal untuk bash nantinya PROMPT_COMMAND="echo foo" bash, kan? Adalah ini kemungkinan untuk pemijahan zsh: ZDOTDIR=/program/dir zsh. Kemudian /program/dir/.zshrcdiperoleh dari awal di mana Anda dapat mendefinisikan kait precmd (). Jika Anda ingin pengguna, sertakan, source $HOME/.zshrcdll. Di zshrc program. Ini harus mudah dipelihara, karena tidak ada file di luar dir program yang dimodifikasi.
mpy

1
@ Shnatsel: Saya memperpanjang jawaban saya. Mungkin Anda juga dapat mengedit pertanyaan Anda untuk memasukkan info tambahan dari komentar Anda.
mpy

5

Seperti yang dinyatakan oleh @mypy, Zsh precmdbekerja mirip dengan Bash PROMPT_COMMAND.

Berikut ini contoh yang berfungsi untuk Bash atau Zsh dan tidak digunakan eval:

## ~/myprompt.sh

# 'ZSH_VERSION' only defined in Zsh
# 'precmd' is a special function name known to Zsh

[ ${ZSH_VERSION} ] && precmd() { myprompt; }

# 'BASH_VERSION' only defined in Bash
# 'PROMPT_COMMAND' is a special environment variable name known to Bash

[ ${BASH_VERSION} ] && PROMPT_COMMAND=myprompt

# function called every time shell is about to draw prompt
myprompt() {
  if [ ${ZSH_VERSION} ]; then
    # Zsh prompt expansion syntax
    PS1='%{%F{red}%}%n%{%f%}@%{%F{red}%}%m %{%F{cyan}%}%~ %{%F{white}%}%# %{%f%}'
  elif [ ${BASH_VERSION} ]; then
    # Bash prompt expansion syntax
    PS1='\[\e[31m\]\u\[\e[0m\]@\[\e[31m\]\h \[\e[36m\]\w \[\e[37m\]\$ \[\e[0m\]'
  fi
}

Jalankan dari skrip init shell:

## ~/.bashrc
. ~/myprompt.sh

dan:

## ~/.zshrc
. ~/myprompt.sh

Prompt di sini hanyalah contoh. Seseorang pasti dapat melakukan banyak hal yang lebih rumit.

Untuk detail pengaturan fungsi prompt, lihat: http://zsh.sourceforge.net/Doc/Release/Functions.html#index-precmd dan http://www.gnu.org/software/bash/manual/bashref.html # Pencetakan-Prompt .

Untuk detail ekspansi cepat, lihat http://zsh.sourceforge.net/Doc/Release/Prompt-Expansion.html dan http://www.gnu.org/software/bash/manual/bashref.html#Printing-a -Prompt .

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.