Come posso eseguire un comando in bash dopo qualsiasi modifica in $ PWD?


10

zsh fornisce alcune belle funzioni hook , anche chpwdper eseguire una funzione dopo che l'utente cambia directory.

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

Sto cercando di emularlo in bash.

vincoli:

  • Deve funzionare in shell interattive e non interattive, il che penso significhi che non può fare affidamento su qualcosa di simile $PROMPT_COMMAND
  • Non può ridefinire cd, perché voglio che funzioni per qualsiasi comando che cambi directory (es., pushdE popd)
  • Deve essere eseguito dopo il comando dell'utente, quindi trap "my_function" DEBUGnon funziona, a meno che non riesca in qualche modo a dire lì "esegui prima il $BASH_COMMANDtrapping, quindi fai questo ..." Vedo che posso evitare l'esecuzione automatica di $BASH_COMMAND if extdebug è abilitato e la funzione trap restituisce 1, ma non credo di voler forzare extdebug, e tornare 1per un comando riuscito (ma modificato) sembra sbagliato.

L'ultima parte - "corri dietro il comando dell'utente" - è ciò che attualmente mi ha lasciato perplesso. Se riesco a eseguire una funzione dopo ogni comando, posso farlo controllare se la directory è cambiata dall'ultima volta che abbiamo controllato. Per esempio:

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
}

Sono sulla buona strada o c'è un modo migliore? Come posso eseguire un comando in bash dopo che l'utente cambia directory?


3
Perché non ridefinire cd, pushde popd? In quanti altri modi ci sono per cambiare directory?
— jw013,

@ jw013 questo codice è destinato a entrare in un progetto open source in cui il manutentore ha elencato specificamente non ridefinendo cdcome principio.
— Nathan Long,

Inoltre - "quanti altri modi ci sono per cambiare directory" - Non lo so, che è un altro motivo per cui preferirei non fare affidamento sul elencarli esplicitamente.
— Nathan Long,

Perchè vuoi fare questo? La tua funzione potrebbe frenare molti programmi (C, Java, ..). Negli script che utilizzo MYBIN=$( cd -P -- "$(dirname -- "$(command -v -- "$0")")" && pwd -P )Si prega di non modificare i comandi Unix attendibili.
— Walter,

1
@NathanLong è solo per il mio sistema operativo . Il sistema operativo sembra irrilevante qui. Il sistema operativo è importante? È la shell che conta nella tua domanda, e sembra che tu stia chiedendo specificamente bash, che funziona praticamente allo stesso modo su tutti i sistemi operativi su cui gira.
— jw013,

Risposte:


2

Non c'è modo che soddisfi questi vincoli

Sembra che non ci sia modo di risolvere questo problema bash con i miei vincoli. In generale, le possibili soluzioni sono:

  • Sostituisci cd, pushde popd, in modo che qualsiasi comando che cambi directory esegua prima la funzione hook. Ma questo può creare problemi perché 1) l'override deve fare attenzione a completare la scheda come il comando originale e restituire lo stesso codice di uscita e 2) se più di uno strumento utilizza questo approccio, non possono giocare bene insieme
  • Sostituisci tutti i comandi che possono essere eseguiti con le modifiche all'ambiente per eseguire prima la funzione hook. Questo è difficile perché ci sono molti di questi comandi
  • 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`, non dopo 3) può esserci solo una funzione di debug, quindi se un altro strumento usa questo approccio, non possono giocare bene insieme
  • Ridefinire $PROMPT_COMMANDper eseguire prima la funzione hook. Questo non è ottimale perché non funzionerà in shell non interattive e perché se un altro strumento definisce il comando prompt, non possono giocare bene insieme.

In breve, sembra che l'unica grande soluzione sarebbe se Bash fornisse qualcosa di simile al chpwd_functionsgancio di Zshell , ma sembra impossibile simularlo correttamente.


1

Se al manutentore non piace cambiare la definizione per cd, un'altra opzione sarebbe quella di ridefinire tutti i comandi che utilizzano questo ambiente in-directory:

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

Ciò sarebbe abbastanza efficiente perché l'hook PWD e la configurazione in-directory verrebbero elaborati solo quando richiesto.

Nella tua funzione check_pwd di esempio, potrei cambiare:

my_function

per:

my_function "$PWD"

per passare al nuovo cwd (potrebbe essere più modulare, testabile).


"ridefinisci tutti i comandi che utilizzano questo ambiente in-directory" Sfortunatamente, non posso prevederlo.
— Nathan Long,

0

Installa gli strumenti inotify in base alla tua distribuzione.

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

Nel mio esempio il seguente comando verrà riavviato httpdse qualcosa cambia (Modifica, Crea, Elimina) nella directory specificata.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.