
zshは良いものを提供しますフック機能、chpwd
ユーザーがディレクトリを変更した後に実行される機能が含まれています。
# zsh only
function greet() { echo 'hi'; }
chpwd_functions+=("greet")
cd .. # hi
pushd # hi
popd # hi
私はこれをbashでエミュレートしようとしています。
制限要因:
- 対話型シェルと非対話型シェルの両方で機能する必要があります。これは、次のことに頼ることができないことを意味すると思います。
$PROMPT_COMMAND
cd
ディレクトリを変更するコマンド(たとえば、pushd
およびpopd
)と連携したいので、上書きすることはできません。- 実行する必要があります後ろにユーザーのコマンドを実行するので、
trap "my_function" DEBUG
「最初に問題のあるコマンドを実行してからこの操作を実行してください...」と言えないと機能しません。$BASH_COMMAND
自動実行を避けることができることがわかりました。$BASH_COMMAND
もしextdebug
有効そしてトラップ関数は1を返しますが、強制的に実行したくないので、成功した(しかし修正された)コマンドをextdebug
返すのは間違っているようです。1
最後の部分である「ユーザーコマンドによる実行」は、現在私を混乱させます。もし私ができる各コマンドの後に関数を実行すると、最後に確認した後にディレクトリが変更されたことを確認できます。たとえば、
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
}
私は正しい道を行っていますか、それとも良い道ですか?ユーザーがディレクトリを変更した後にbashでコマンドを実行する方法は?
答え1
これらの制約を満たす方法はありません
私の制限を考えると、bashはこの問題を解決する方法がないようです。一般的に考えられる解決策は次のとおりです。
cd
、pushd
およびをオーバーライドして、ディレクトリpopd
を変更するすべてのコマンドにフック機能を最初に実行させます。ただし、これは問題を引き起こす可能性があります。 1)オーバーライドは元のコマンドと同じくらい慎重に実行し、同じ終了コードを返す必要があります。2)複数のツールがこのアプローチを使用している場合、それはうまく機能しません。- フック機能を最初に実行するには、環境が変更されたときに実行される可能性のあるすべてのコマンドをオーバーライドします。このような命令がたくさんあるので難しいです。
trap 'my_function' DEBUG
これにより、すべてのコマンドがフック機能を実行します。これは、1) すべての命令の前に実行され、2) 実行されるため、次善策です。今後cd
、代わりに3)デバッグ機能は1つしかないため、他のツールでこのアプローチを使用すると一緒にうまく機能しません。$PROMPT_COMMAND
まず、実行するHook関数をオーバーライドします。これは非対話型シェルでは機能しないため、他のツールでプロンプトコマンドを定義した場合はうまく機能しないため、これは最適です。
簡単に言えば、bashがchpwd_functions
zshellフックのようなものを提供することは唯一の良い解決策であるようですが、それを正しくエミュレートすることは不可能です。
答え2
管理者がcd定義を変更することを好まない場合は、別のオプションは、このディレクトリ内で環境を使用するすべてのコマンドをオーバーライドすることです。
for c in cmd1 cmd2 cmd3 cmd4 cmd5 ; do
eval "$c() { check_pwd ; command $c \"\$@\" ; }"
done
PWDフックとディレクトリ内の構成は必要なときにのみ処理されるため、これは非常に効率的です。
あなたの例のcheck_pwd関数では、以下を変更できます。
my_function
到着する:
my_function "$PWD"
新しいcwdを通過するために(おそらくよりモジュール化され、テスト可能です)。
答え3
インストールするイノティファイツールディストリビューションによって異なります。
inotifywait -emodify,create,delete -m /path/to/directory | while read line; do service httpd reload; done
httpd
私の例では、指定されたディレクトリに変更(変更、作成、削除)が発生すると、次のコマンドが再起動されます。