実行前にZsh / Bashのすべてのコマンドをカスタムコマンドに自動的にラップする方法は?

実行前にZsh / Bashのすべてのコマンドをカスタムコマンドに自動的にラップする方法は?

Zsh実行前に、Bashすべての入力にカスタムコマンド(名前付けなど)を自動的に追加するために、シェルの動作を変更(または)しようとしています。myappデフォルトでは、ユーザーの入力を傍受して変更し、ユーザーがを押すと、変更されたENTER_KEYコマンドを実行する必要があります。

シェルに入力するすべてのコマンドは次のとおりです。

grep -rn hello

私が入力したように処理する必要があります。

$ myapp grep -rn hello

別の例として、 を入力するとlsで実行する必要がありますmyapp ls

ターゲット

いくつかのcliツールのビューアでvimを自動的に試してみたいです。

# myapp
vim -c "term $*"

答え1

目標を考慮する際の最も簡単な解決策は、以下のようにコマンドの結果をvimにパイプすることです。

$ yourcommand | vim -

例えば、

$ grep -rn hello | vim -

答え2

私はあなたがこの配列に入って出て行きたいとし、次のことをしました。 zsh の場合、DEBUG トラップ・ハンドラーは ERR_EXIT オプションを設定することによって、サブミットされたコマンドの実行をスキップし、代わりにカスタム・コマンドを実行できます。

# this is run before every command
debug_trap() {
    # get last submitted command
    cmd="${history[$HISTCMD]}";
    if [ "$cmd" ]; then
        # catch the unwrap command and remove the trap
        if [ "$cmd" = "unwrap" ]; then
            print 'Unwrapping command-line';
            trap - DEBUG;
            return;
        fi
        # make sure multiple trap triggers only handle this once
        if [ "$handled" != "$HISTCMD;$cmd" ]; then
            # when either history index or command text
            # changes, we can assume its a new command
            handled="$HISTCMD;$cmd";
            # do whatever with $cmd
            myapp $cmd;
        fi
        # optionally skip the raw execution
        setopt ERR_EXIT;
    fi
}

# start the debug trap
wrap() {
    print 'Wrapping command-line';
    trap 'debug_trap' DEBUG;
}

# this is just defined in order to avoid errors
# the unwrapping happens in the trap handler
unwrap() {}

Bashと同じ:

# bash requires this option in order to skip execution
# inside the debug trap
shopt -s extdebug;

# this is run before every command
debug_trap() {
    cmd="$BASH_COMMAND";
    # catch the unwrap command and remove the trap
    # notice how the alias is expanded here and
    # the command is no longer 'unwrap'
    if [[ "$cmd" == 'trap - DEBUG' ]]; then
        echo 'Unwrapping command-line';
        # the trap is unset by the submitted command
    else
        # do whatever with $cmd
        myapp $cmd;
        # optionally skip the raw execution
        return 1;
    fi
}

# start the debug trap
wrap() {
    echo 'Wrapping command-line';
    trap debug_trap DEBUG;
}

# we can't unset global traps inside a function
# so we use an alias instead
alias unwrap='trap - DEBUG';

使用例:

> myapp() { echo "### $1"; }
> wrap
Wrapping command-line
> echo 123
### echo 123
> unwrap
Unwrapping command-line
> echo 123
123

vim機能を実装するには、myapp関数で "vim -c"を使用するか、トラップ関数で "myapp $ cmd;"行を変更してください。

ただし、使用前の注意事項です。デバッグトラップは非常に難しいので、エラーを減らすためにzshバージョンを試しました。 oh-my-*shなどのプラグインを使用すると、信頼性の高い実装を達成するのに困難を大幅に増やすフック、トラップ、およびその他のメカニズムを導入できます。 zshバージョンはoh-my-zshに対してテストされており、機能する必要があります。 bashのバージョンは修正されていないbash v4.2でのみテストされました。

zshの他の潜在的な実装:テキストバッファを実行する前に操作する戻りキーにバインドされているデフォルトのzleウィジェット「accept-line」をオーバーライドすることができ、これはよりきれいな解決策かもしれません。役に立つ「preexec」フック機能もありますが、独自にコマンドを変更したりスキップしたりする方法はないようです。

その他の使用のアイデア:1つ以上のリモートシステムに(ssh)コマンドを送信したり、スクリプトファイルに書き込んで実行を延期したり、実行前に静的分析を実行したり、確認を要求したり、誤字修正を要求したりするために使用できます。

関連情報