うん!あなたはアイデアを持っています。
コマンド ラインで C コンパイラを使用する場合、 cc [filename] と入力すると、シェルが fork() システム コールを使用してプロセスを複製し、exec() システム コールが cc コンパイラ実行可能ファイルを子プロセスのコア イメージ。次に、シェルを実行している親プロセスが待機している間、cc 実行可能ファイルを含む子プロセスが処理を実行します。そうですか?
それは正しい。親プロセス (シェル) はwait()
、子の PID を呼び出し、終了するのを待ちます。
cp、mv、ls などのシェル コマンドはどうでしょうか。彼らは何ですか?それらは、シェルによってフォークされた新しい子プロセスでも実行される実行可能プログラムですか?
同じこと。これらはコンパイラのようなバイナリであり、シェルはそれらに対して同じことを行います。
現在、「ビルトイン」と呼ばれる外部バイナリではないコマンドがいくつかあります。これらは、シェルがそれ自体を認識するコマンドであり、外部バイナリを呼び出す必要はありません。なんで?
if
andのような特別な構文を持つものもあるwhile
ため、必然的にシェルに組み込む必要があります。
cd
やなどの一部はread
、シェル プロセスの状態を変更するため、組み込みである必要があります。(外部バイナリがシェルの現在のディレクトリを変更することは不可能です。フォークされたプロセスは、親の PWD ではなく、自身の PWD しか変更できないためです。)
echo
やのような他のものは、printf
別個のバイナリである可能性があり、たまたまシェルによって実装されているだけです。
入力から取得した bash ビルトインの完全なリストを次に示しますhelp
。
job_spec [&] history [-c] [-d offset] [n] or history -anrw [filename] or histor>
(( expression )) if COMMANDS; then COMMANDS; [ elif COMMANDS; then COMMANDS; ]... [>
. filename [arguments] jobs [-lnprs] [jobspec ...] or jobs -x command [args]
: kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill>
[ arg... ] let arg [arg ...]
[[ expression ]] local [option] name[=value] ...
alias [-p] [name[=value] ... ] logout [n]
bg [job_spec ...] mapfile [-n count] [-O origin] [-s count] [-t] [-u fd] [-C callbac>
bind [-lpvsPVS] [-m keymap] [-f filename] [-q name] [-u name] [-r k> popd [-n] [+N | -N]
break [n] printf [-v var] format [arguments]
builtin [shell-builtin [arg ...]] pushd [-n] [+N | -N | dir]
caller [expr] pwd [-LP]
case WORD in [PATTERN [| PATTERN]...) COMMANDS ;;]... esac read [-ers] [-a array] [-d delim] [-i text] [-n nchars] [-N nchars>
cd [-L|[-P [-e]]] [dir] readarray [-n count] [-O origin] [-s count] [-t] [-u fd] [-C callb>
command [-pVv] command [arg ...] readonly [-aAf] [name[=value] ...] or readonly -p
compgen [-abcdefgjksuv] [-o option] [-A action] [-G globpat] [-W w> return [n]
complete [-abcdefgjksuv] [-pr] [-DE] [-o option] [-A action] [-G gl> select NAME [in WORDS ... ;] do COMMANDS; done
compopt [-o|+o option] [-DE] [name ...] set [-abefhkmnptuvxBCHP] [-o option-name] [--] [arg ...]
continue [n] shift [n]
coproc [NAME] command [redirections] shopt [-pqsu] [-o] [optname ...]
declare [-aAfFgilrtux] [-p] [name[=value] ...] source filename [arguments]
dirs [-clpv] [+N] [-N] suspend [-f]
disown [-h] [-ar] [jobspec ...] test [expr]
echo [-neE] [arg ...] time [-p] pipeline
enable [-a] [-dnps] [-f filename] [name ...] times
eval [arg ...] trap [-lp] [[arg] signal_spec ...]
exec [-cl] [-a name] [command [arguments ...]] [redirection ...] true
exit [n] type [-afptP] name [name ...]
export [-fn] [name[=value] ...] or export -p typeset [-aAfFgilrtux] [-p] name[=value] ...
false ulimit [-SHacdefilmnpqrstuvx] [limit]
fc [-e ename] [-lnr] [first] [last] or fc -s [pat=rep] [command] umask [-p] [-S] [mode]
fg [job_spec] unalias [-a] name [name ...]
for NAME [in WORDS ... ] ; do COMMANDS; done unset [-f] [-v] [name ...]
for (( exp1; exp2; exp3 )); do COMMANDS; done until COMMANDS; do COMMANDS; done
function name { COMMANDS ; } or name () { COMMANDS ; } variables - Names and meanings of some shell variables
getopts optstring name [arg] wait [id]
hash [-lr] [-p pathname] [-dt] [name ...] while COMMANDS; do COMMANDS; done
help [-dms] [pattern ...] { COMMANDS ; }
ビルトインの他に、関数とエイリアスもあります。これらは、個別のスクリプト/バイナリを作成することなく、新しい機能を定義する方法です。
uppercase() {
tr '[:lower:]' '[:upper:]' <<< "$*"
}
alias ls='ls --color=auto -F'
関数とエイリアスは通常、利便性のためか、補助機能を追加するためのものです。
シェルスクリプトはどうですか?... コマンドラインは新しいプロセスを fork() し、新しいプロセスでこのスクリプトを exec() しますか? そして、スクリプト fork() を含むこの新しいプロセスは、日付、cc コンパイラなどを実行する他のプロセスを実行しますか??
はい、まさにその通りです。シェル スクリプトが実行されると、親シェルが子プロセスをフォークし、そこでスクリプトが実行されます。スクリプト内のコマンドは、したがって、この子プロセスからフォークされました。それらは元のシェルの孫です。