Bash組み込みで「exec」を実行する


9

シェル関数を定義します(clockこれをと呼びましょう)。これは、time関数と同様に、別のコマンドのラッパーとして使用したいものですclock ls -R

私のシェル関数はいくつかのタスクを実行してから終了しexec "$@"ます。

この関数をシェルのビルトインでも機能させたいのです。たとえば、実行可能ファイルではなく、ビルトインclock time ls -Rの結果を出力する必要がtimeあり/usr/bin/timeます。しかし、exec常に代わりにコマンドを実行することになります。

Bash関数を引数としてシェル組み込みを受け入れるラッパーとして機能させるにはどうすればよいですか?

編集:これtimeはBashの組み込みではなく、パイプラインに関連する特別な予約語であることを学びました。で動作しない場合でも、組み込みのソリューションに関心がありますtimeが、より一般的なソリューションの方が優れています。


を使用して、シェルを明示的に呼び出す必要がありexec bash -c \' "$@" \'ます。最初のパラメーターのコマンドがシェルスクリプトとして認識されない限り、直接実行されるバイナリとして解釈されます。代わりに、もっと簡単に言えば、を外して元のシェルからexec呼び出すだけ"@"です。
AFH 2015

回答:


9

bash関数を定義しました。そのため、その関数を呼び出すときには、すでにbashシェルに入っています。したがって、その関数は単純に次のようになります。

clock(){
  echo "do something"
  $@
}

その関数は、bashビルトイン、特別な予約語、コマンド、その他の定義済み関数で呼び出すことができます。

エイリアス:

$ clock type ls
do something
ls is aliased to `ls --color=auto'

組み込みのbash:

$ clock type type
do something
type is a shell builtin

別の機能:

$ clock clock
do something
do something

実行可能ファイル:

$ clock date
do something
Tue Apr 21 14:11:59 CEST 2015

この場合、実行している間に何らかの差がある$@exec $@、私は私が実際にコマンドを実行しています知っている場合は、?
アルコール2015

3
を使用するexecと、コマンドがシェルを置き換えます。したがって、実行可能ファイルはシステムコールを介して実行されるため、ビルトイン、エイリアス、特別な予約語、定義された語はもうありませんexecve()。そのsyscallは実行可能ファイルを想定しています。
2015

しかし、外部の観察者の視点から、で例えば、それらを区別することは可能であるexec $0、単一のプロセスがある一方で、$@まだ2を持っています。
アルコール2015

4
はい、$@実行中のシェルを親として、コマンドを子プロセスとして持っています。ただし、ビルトインやエイリアスなどを使用する場合は、シェルを保持する必要があります。または、新しいものを開始します。
2015

4

シェル組み込みコマンドまたはシェルキーワードを起動する唯一の方法は、execが「指定されたコマンドでシェルを置き換える」ため、新しいシェルを起動することです。最後の行を次のように置き換える必要があります。

IFS=' '; exec bash -c "$*"

これは組み込みと予約語の両方で機能します。原理は同じです。


3

ラッパーが所定のコマンドのにコードを挿入する必要がある場合、非常に早い段階でエイリアスが展開されるため、エイリアスが機能します。

alias clock="do this; do that;"

エイリアスはエイリアスされた単語の代わりに文字通りほとんど挿入されているので、末尾;が重要です–にclock time foo展開されdo this; do that; time fooます。

これを悪用して、引用をバイパスする魔法のエイリアスを作成できます。


コマンドの後にコード挿入するには、「DEBUG」フックを使用できます。

shopt -s extdebug
trap "<code>" DEBUG

具体的には:

shopt -s extdebug
trap 'if [[ $BASH_COMMAND == "clock "* ]]; then
          eval "${BASH_COMMAND#clock }"; echo "Whee!"; false
      fi' DEBUG

フックはまだコマンドのに実行されますが、返さfalseれるとbashに実行をキャンセルするように指示します(フックはevalを介してすでに実行しているため)。

別の例として、これを次のエイリアスcommand pleaseに使用できますsudo command

trap 'case $BASH_COMMAND in *\ please) eval sudo ${BASH_COMMAND% *}; false; esac' DEBUG

1

これまでに思いついた唯一の解決策は、最初の引数がコマンド、組み込み、またはキーワードであるかどうかを区別するためにケース分析を実行し、最後のケースで失敗することです。

#!/bin/bash

case $(type -t "$1") in
  file)
    # do stuff
    exec "$@"
    ;;
  builtin)
    # do stuff
    builtin "$@"
    ;;
  keyword)
    >&2 echo "error: cannot handle keywords: $1"
    exit 1
    ;;
  *)
    >&2 echo "error: unknown type: $1"
    exit 1
    ;;
esac

timeただし、は処理されないため、より優れた(そしてより簡潔な)ソリューションが存在する可能性があります。

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