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.