cd
あるPOSIXによって義務付けられたシェルの組み込みは:
単純なコマンドの結果、コマンド名とオプションの引数リストが生成される場合、次のアクションが実行されます。
- コマンド名にスラッシュが含まれていない場合、次のシーケンスで最初に成功するステップが発生します:
...
- コマンド名が次の表にリストされているユーティリティの名前と一致する場合、そのユーティリティが呼び出されます。
...
cd
...
- それ以外の場合、コマンドはPATHを使用して検索されます...
これは明示的に組み込みである必要があるとは言いませんが、仕様書は次の記述でcd
続けています:
cdは現在のシェル実行環境に影響を与えるため、常にシェルの標準ビルトインとして提供されます。
bash
マニュアルから:
次のシェル組み込みコマンドは、Bourneシェルから継承されます。これらのコマンドは、POSIX標準の指定に従って実装されます。
...
cd
cd [-L|[-P [-e]]] [directory]
ビルトインである必要のcd
ないアーキテクチャを考えることができると思います。ただし、組み込みの意味を確認する必要があります。何らかのコマンドのために何かをするためにシェルで特別なコードを書くと、ビルトインに近づいています。あなたがやるほど、単にビルトインする方が良いです。
たとえば、シェルにサブプロセスと通信するIPCを持たせることができます。またcd
、ディレクトリの存在と、アクセスする権限があるかどうかを確認し、シェルと通信してその変更を指示するプログラムがあります。ディレクトリ。ただし、その後、あなたと通信しているプロセスが子であるか(または、特別なファイル記述子、共有メモリなど、子とのみ通信する特別な手段を作成するか)、プロセスが実際にあるかどうかを確認する必要があります信頼できるcd
プログラムなどを実行します。それはワームの全体の缶です。
またはcd
、chdir
システムを呼び出して、現在のすべての環境変数を新しいシェルに適用して新しいシェルを開始し、完了時に親シェルを(なんとかして)終了するプログラムを作成することもできます。1
さらに悪いことには、プロセスが他のプロセスの環境を変更できるシステムさえあります(技術的には、デバッガーでこれを行うことができると思います)。ただし、このようなシステムは非常に脆弱です。
このようなメソッドをセキュリティで保護するためにコードを追加することが多くなり、単に組み込みにする方がはるかに簡単です。
何かが実行可能ファイルであることは、それが組み込みであることを妨げません。適例:
echo
そして test
echo
およびtest
POSIXが義務付けているユーティリティ(/bin/echo
および/bin/test
)です。しかし、ほとんどすべての人気のあるシェルには組み込みecho
とtest
。同様に、kill
プログラムとしても利用可能なビルトインです。その他には以下が含まれます:
sleep
(一般的ではない)
time
false
true
printf
ただし、コマンドが組み込み以外のものになれない場合があります。それらの1つですcd
。通常、フルパスが指定されておらず、コマンド名が組み込みコマンドの名前と一致する場合、そのコマンドに適した関数が呼び出されます。シェルに応じて、組み込みの行動と実行のそれは、これは特にです(異なる場合がありますのための問題echo
がある、乱暴に異なる行動を。あなたが行動の特定になりたい場合は、実行ファイルが使用して呼び出すことが望ましいですフルパス、次のような変数を設定しますPOSIXLY_CORRECT
(それでも実際の保証はありません)。
技術的には、シェルでもあり、すべてのコマンドが組み込みのOSを提供することを妨げるものはありません。この極端な終わりに近いのは、モノリシックなBusyBoxです。BusyBoxは単一のバイナリで、(呼び出される名前に応じて)Almquist Shell()を含む240以上のプログラムのいずれかとして動作できますash
。PATH
BusyBoxの実行中に設定を解除しても、BusyBox ash
で使用可能なプログラムには、.yを指定しなくてもアクセスできますPATH
。シェル自体がBusyBoxの一種のビルトインであることを除けば、シェル組み込みに近いものになります。
dash
ソースを見ると、実行スレッドは次のようなものです(もちろん、パイプやその他のものを使用する場合は追加の機能が含まれます)。
main
→ cmdloop
→ evaltree
→evalcommand
evalcommand
次にfindcommand
、コマンドが何であるかを決定するために使用します。それは組み込みであれば、その後:
case CMDBUILTIN:
if (spclbltin > 0 || argc == 0) {
poplocalvars(1);
if (execcmd && argc > 1)
listsetvar(varlist.list, VEXPORT);
}
if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
if (exception == EXERROR && spclbltin <= 0) {
FORCEINTON;
break;
cmdentry.u.cmd
はstruct
(struct builtincmd
)であり、そのメンバーの1つは、次の典型的なシグネチャを持つ関数ポインターmain
です(int, char **)
。evalbltin
(組み込みであるか否かに応じて、関数呼び出しeval
のいずれかコマンドかどうか)evalcmd
、またはこの関数ポインタ。実際の関数は、さまざまなソースファイルで定義されています。echo
例えば、あります:
int
echocmd(int argc, char **argv)
{
int nonl;
nonl = *++argv ? equal(*argv, "-n") : 0;
argv += nonl;
do {
int c;
if (likely(*argv))
nonl += print_escape_str("%s", NULL, NULL, *argv++);
if (nonl > 0)
break;
c = *argv ? ' ' : '\n';
out1c(c);
} while (*argv);
return 0;
}
このセクションのソースコードへのリンクはすべて行番号ベースであるため、予告なく変更される場合があります。
1 POSIXシステムにはcd
実行可能ファイルがあります。
サイドノート:
UnixおよびLinuxには、シェルの動作を扱う多くの優れた投稿があります。特に:
これまでにリストされた質問のパターンに気付いていない場合、それらのほぼすべてにステファンシャゼラスが関係しています。
type
コマンドを使用することをお勧めします