web-dev-qa-db-ja.com

シェル組み込みコマンドについて

bash manual には、

Builtin commands are contained >>> within <<< the Shell itself

また、 this 回答では、

A built-in command is simply a command that the Shell carries out itself,
instead of interpreting it as a request to load and run some
>>> other program <<<

compgen -bbash 4.4を実行すると、すべてのシェル組み込みコマンドのリストが表示されます。たとえば、[killがShellビルトインとしてリストされていることがわかります。しかし、実際の場所は次のとおりです。

/usr/bin/[
/bin/kill

builtinは、コマンドが/bin/bash実行可能ファイルにコンパイルされることを意味すると思いました。だから私を本当に混乱させているのは何ですか:私を訂正してください、しかしそれが実際にシェルの一部ではない場合、どのようにして別のコマンドをbuiltinにすることができますか?

12
manifestor

シェルに組み込まれているコマンドは、パフォーマンスが向上するために組み込まれていることがよくあります。たとえば、externalprintfの呼び出しは、組み込みのprintfを使用するよりも低速です。

一部のユーティリティはneedを組み込まないため、cdのような特別なものでない限り、-externalユーティリティとしても提供されます。これは、組み込みの同等機能を提供しないシェルによってスクリプトが解釈されてもスクリプトが壊れないようにするためです。

一部のシェルのビルトインは、外部の同等のコマンドに対する拡張機能も提供します。 Bashのprintfなど。

_$ printf -v message 'Hello %s' "world"
$ echo "$message"
Hello world
_

(変数に出力する)外部_/usr/bin/printf_は、現在のシェルセッションでシェル変数にアクセスできないため(そしてそれらを変更できないため)、これを行うことはできません。

組み込みユーティリティにはnotもあり、拡張されたコマンドラインは特定の長さよりも短くなければならないという制限があります。している

_printf '%s\n' *
_

したがって、printfがシェル組み込みコマンドである場合は安全です。コマンドラインの長さの制限は、外部コマンドの実行に使用されるexecve() Cライブラリ関数に起因します。コマンドラインと現在の環境が_ARG_MAX_バイトより大きい場合(シェルの_getconf ARG_MAX_を参照)、execve()の呼び出しは失敗します。ユーティリティがシェルに組み込まれている場合、execve()を呼び出す必要はありません。

組み込みユーティリティは、_$PATH_にあるユーティリティよりも優先されます。 bashの組み込みコマンドを無効にするには、たとえば、.

_enable -n printf
_

needがシェルに組み込まれるユーティリティの短いリストがあります(POSIX標準の 特別な組み込みのリスト から取得)

_break
colon (:)
continue
dot (.)
eval
exec
exit
export
readonly
return
set
shift
times
trap
unset
_

これらは、現在のシェルセッションの環境とプログラムフローを直接操作するため、組み込みが必要です。外部のユーティリティはそれを行うことができません。

興味深いことに、cdはこのリストの一部ではありませんが、POSIX 次のように言います については、

cdは現在のシェル実行環境に影響を与えるため、常に通常のシェル組み込みとして提供されます。次のいずれかなど、サブシェルまたは別のユーティリティ実行環境で呼び出された場合:

_(cd /tmp)
Nohup cd
find . -exec cd {} \;
_

呼び出し元の環境の作業ディレクトリには影響しません。

したがって、「特別な」ビルトインは外部の対応物を持つことができないと想定していますが、cdは理論的にはそうすることができます(ただし、あまり機能しません)。

16
Kusalananda

一部のビルトイン両方がビルトインとして存在するおよびが外部コマンドとして存在するという事実に(非常に理解できるほど)混乱しています。したがって、たとえば/bin/[コマンドがあるというのは正しいですが、「実際の場所」が/binにあるという意味ではありません。

これをテストする簡単な方法は、type-aスイッチで実行して、コマンドのすべての使用可能なインスタンスを表示することです。私のArchシステムでは次のように表示されます:

$ type -a [
[ is a Shell builtin
[ is /sbin/[
[ is /usr/sbin/[
[ is /usr/bin/[

/sbin/usr/sbin/binはすべて/usr/binを指すシンボリックリンクであるため、外部[は1つだけであることに注意してください。

$ readlink -f /usr/sbin /sbin /bin/
/usr/bin
/usr/bin
/usr/bin

ご覧のとおり、[は組み込みコマンドと外部コマンドの両方であり、同じことが他のさまざまなシェル組み込みコマンドにも当てはまります。ただし、これらはシェル自体にコンパイルされた組み込みシェルでもあるという事実は変わりません。

7
terdon