Bagaimana saya bisa menjalankan perintah dalam bash setelah ada perubahan $ PWD?

10

zsh menyediakan beberapa fungsi kait yang bagus , termasuk chpwdmenjalankan fungsi setelah pengguna mengubah direktori.

# zsh only
function greet() { echo 'hi'; }
chpwd_functions+=("greet")
cd .. # hi
pushd # hi
popd  # hi

Saya mencoba untuk meniru di bash

Kendala:

  • Itu harus bekerja di kedua shell interaktif dan non-interaktif, yang saya pikir berarti itu tidak dapat bergantung pada sesuatu seperti $PROMPT_COMMAND
  • Itu tidak dapat mendefinisikan ulang cd, karena saya ingin itu berfungsi untuk perintah apa pun yang mengubah direktori (misalnya, pushddan popd)
  • Itu harus dijalankan setelah perintah pengguna, jadi trap "my_function" DEBUGtidak bekerja, kecuali saya entah bagaimana bisa mengatakan di sana, "pertama jalankan $BASH_COMMANDkita terjebak, kemudian juga melakukan ini ..." Saya melihat bahwa saya dapat menghindari menjalankan otomatis $BASH_COMMAND jika extdebug diaktifkan dan fungsi trap mengembalikan 1, tetapi saya tidak berpikir saya ingin memaksakan extdebug, dan kembali 1untuk perintah yang berhasil (tetapi dimodifikasi) tampaknya salah.

Bagian terakhir - "jalankan setelah perintah pengguna" - adalah apa yang saat ini membuat saya bingung. Jika saya dapat menjalankan fungsi setelah setiap perintah, saya dapat memeriksanya apakah direktori telah berubah sejak kami terakhir memeriksa. Misalnya:

function check_pwd() {
  # true in a new shell (empty var) or after cd
  if [ "$LAST_CHECKED_DIR" != "$PWD" ]; then
    my_function
  fi
  LAST_CHECKED_DIR=$PWD
}

Apakah saya di jalur yang benar, atau ada cara yang lebih baik? Bagaimana saya bisa menjalankan perintah dalam bash setelah pengguna mengubah direktori?

Nathan Long
sumber
3
Mengapa tidak mendefinisikan cd, pushddan popd? Berapa banyak cara lain untuk mengubah direktori?
jw013
@ jw013 kode ini dimaksudkan untuk masuk ke proyek open source di mana pengelola secara khusus terdaftar tidak mendefinisikan ulang cdsebagai prinsip.
Nathan Long
Juga - "berapa banyak cara lain untuk mengubah direktori" - Saya tidak tahu, yang merupakan alasan lain saya lebih suka untuk tidak bergantung pada daftar mereka secara eksplisit.
Nathan Long
Mengapa Anda ingin melakukan ini? Fungsi Anda mungkin mengerem banyak program (C, Java, ..). Dalam skrip yang saya gunakan MYBIN=$( cd -P -- "$(dirname -- "$(command -v -- "$0")")" && pwd -P )Tolong jangan mengubah perintah Unix tepercaya.
Walter A
1
@ NathanLong itu hanya untuk sistem operasi saya . Sistem operasi tampaknya tidak relevan di sini. Apakah OS itu penting? Ini shell yang penting dalam pertanyaan Anda, dan Anda tampaknya secara khusus bertanya tentang bash, yang bekerja hampir sama pada semua sistem operasi yang berjalan.
jw013

Jawaban:

2

Tidak ada cara yang memenuhi kendala ini

Sepertinya tidak ada cara untuk menyelesaikan masalah ini di bash dengan kendala saya. Secara umum, solusi yang mungkin adalah:

  • Override cd,, pushdand popd, sehingga perintah apa pun yang mengubah direktori akan menjalankan fungsi hook terlebih dahulu. Tapi ini bisa menimbulkan masalah karena 1) override harus hati-hati untuk menyelesaikan tab seperti perintah asli dan mengembalikan kode keluar yang sama dan 2) jika lebih dari satu alat mengambil pendekatan ini, mereka tidak bisa bermain bersama dengan baik
  • Timpa semua perintah yang mungkin dijalankan dengan perubahan lingkungan untuk pertama-tama menjalankan fungsi hook. Ini sulit karena ada banyak perintah seperti itu
  • trap 'my_functionDEBUG so that every command will run the hook function. This is suboptimal because 1) it runs before every command, 2) it runs *before*cd`, bukan setelah 3) hanya ada satu fungsi debug, jadi jika alat lain menggunakan pendekatan ini, mereka tidak bisa bermain bersama dengan baik
  • Tetapkan ulang $PROMPT_COMMANDuntuk menjalankan fungsi kait terlebih dahulu. Ini adalah suboptimal karena itu tidak akan bekerja di shell non-interaktif, dan karena jika alat lain mendefinisikan perintah prompt, mereka tidak dapat bermain bersama dengan baik.

Singkatnya sepertinya satu-satunya solusi yang bagus adalah jika bash menyediakan sesuatu seperti chpwd_functionskait zshell , tetapi tampaknya mustahil untuk mensimulasikannya dengan benar.

Nathan Long
sumber
1

Jika pengelola tidak suka Anda mengubah definisi untuk cd, opsi lain adalah mendefinisikan ulang semua perintah yang menggunakan lingkungan dalam direktori ini:

for c in cmd1 cmd2 cmd3 cmd4 cmd5 ; do
    eval "$c() { check_pwd ; command $c \"\$@\" ; }"
done

Ini akan sangat efisien karena hook PWD dan konfigurasi dalam direktori hanya akan diproses bila diperlukan.

Dalam fungsi check_pwd contoh Anda, saya mungkin berubah:

my_function

untuk:

my_function "$PWD"

untuk lulus di cwd baru (mungkin lebih modular, dapat diuji).

Gregor
sumber
"mendefinisikan ulang semua perintah yang menggunakan lingkungan dalam direktori ini" Sayangnya, saya tidak dapat memprediksi itu.
Nathan Long
0

Instal inotify-tools sesuai dengan distribusi Anda.

inotifywait -emodify,create,delete -m /path/to/directory | while read line; do service httpd reload; done

Dalam contoh saya, perintah berikut akan memulai ulang httpdjika ada perubahan (Ubah, Buat, Hapus) di direktori yang ditentukan.

Ali Pandidan
sumber