$ PWDを変更した後、bashでコマンドを実行するにはどうすればよいですか?


10

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有効になっていますそして、trap関数は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でコマンドを実行するにはどうすればよいですか?


3
なぜ再定義していないcdpushdpopd?ディレクトリを変更する方法は他にいくつありますか?
jw013 14

@ jw013このコードは、メンテナーがcd原則として再定義しないことを具体的にリストしたオープンソースプロジェクトに移行することを目的としています。
Nathan Long

また、「ディレクトリを変更する方法は他にいくつありますか」-わかりません。これは、明示的にリストすることに依存したくない別の理由です。
Nathan Long

なぜこれをしたいのですか?関数が多くのプログラム(C、Javaなど)にブレーキをかける可能性があります。私が使用するスクリプトではMYBIN=$( cd -P -- "$(dirname -- "$(command -v -- "$0")")" && pwd -P )、信頼できるUnixコマンドを変更しないでください。
Walter A

1
@NathanLong は、私のオペレーティングシステム専用です。ここではオペレーティングシステムは無関係のようです。OSは重要ですか?それはあなたの質問で重要なシェルであり、あなたは具体的に尋ねているようbashです、それはそれが実行されるすべてのオペレーティングシステムでほとんど同じように機能します。
jw013 14

回答:


2

これらの制約を満たす方法はありません

私の制約でbashでこの問題を解決する方法はないようです。一般に、可能な解決策は次のとおりです。

  • 、、およびをオーバーライドしてcd、ディレクトリを変更するコマンドが最初にフック関数を実行するようにします。しかし、これは問題を引き起こす可能性があります。1)オーバーライドは、元のコマンドのようにタブを完了して同じ終了コードを返すように注意する必要があり、2)複数のツールがこのアプローチを取る場合、それらはうまく連携できないpushdpopd
  • 最初にフック関数を実行するために、環境変更で実行される可能性のあるすべてのコマンドをオーバーライドします。そのようなコマンドがたくさんあるので、これは難しいです
  • 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`、3以降ではありません。デバッグ関数は1つしか存在できないため、別のツールがこのアプローチを使用すると、それらはうまく機能しません。
  • $PROMPT_COMMANDフック関数を最初に実行するように再定義します。これは非対話型シェルでは機能しないため、また別のツールがプロンプトコマンドを定義している場合、それらがうまく連携できないため、最適ではありません。

簡単に言えば、bashがzshellのchpwd_functionsフックのようなものを提供した場合、唯一の優れた解決策であるように見えますが、それを適切にシミュレートすることは不可能のようです。


1

メンテナが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を渡すために(よりモジュール化され、テスト可能かもしれません)。


「このディレクトリ内環境を使用するすべてのコマンドを再定義する」残念ながら、それを予測することはできません。
Nathan Long

0

ディストリビューションに応じてinotify-toolsをインストールします。

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

私の例httpdでは、指定したディレクトリで何か変更(変更、作成、削除)があった場合、次のコマンドが再起動します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.