Luc*_*ira 3 shell executable system-calls
我试图了解程序,shell命令和操作系统的工作原理.请原谅我的无知,因为我是新手.
当我在命令行上使用C编译器时,当我输入cc [filename]时,我认为shell使用fork()系统调用来复制其进程,然后exec()系统调用将cc编译器可执行文件加载到儿童过程的核心形象.然后,包含cc可执行文件的子进程将执行其操作,而执行shell的父进程是否等待.这样对吗?
那些shell命令如cp,mv,ls等等.这些是什么?它们是可执行程序,也将在shell分叉的新子进程中执行吗?shell脚本怎么样?假设我创建了一个像这样的简单shell脚本(请忽略任何我不知道如何执行此操作的错误):
echo "Hello"
date
echo
cc -o test file1.c file2.c file3.c
Run Code Online (Sandbox Code Playgroud)
然后我使用命令行执行此脚本.请问命令行fork()一个新进程和exec()这个脚本在新进程中?然后这个新进程会包含脚本fork()其他进程来执行date,cc编译器等吗?
我希望这听起来不会太混乱,因为我= /.
是的!你有这个想法.
当我在命令行上使用C编译器时,当我输入cc [filename]时,我认为shell使用fork()系统调用来复制其进程,然后exec()系统调用将cc编译器可执行文件加载到儿童过程的核心形象.然后,包含cc可执行文件的子进程将执行其操作,而执行shell的父进程是否等待.这样对吗?
那就对了.父进程(shell)调用子进程wait()的PID并等待它退出.
那些shell命令如cp,mv,ls等等.这些是什么?它们是可执行程序,也将在shell分叉的新子进程中执行吗?
一样.这些是二进制文件,就像编译器一样,shell也为它们做同样的事情.
现在有一些命令不是外部二进制文件,称为"内置函数".这些是shell识别自身的命令,不需要为外部二进制文件调用.为什么?
if和while,因此必须在shell中构建.cd和read更改shell进程的状态,因此必须内置.(外部二进制文件不可能更改shell的当前目录,因为分叉进程只能更改自己的PWD,而不能更改它们的父进程.)echo和printf,可能是单独的二进制文件,恰好由shell实现.这是我输入的bash builtins的完整列表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 ; }
Run Code Online (Sandbox Code Playgroud)
除了内置函数,还有函数和别名.这些是定义新功能的方法,无需创建单独的脚本/二进制文件.
uppercase() {
tr '[:lower:]' '[:upper:]' <<< "$*"
}
alias ls='ls --color=auto -F'
Run Code Online (Sandbox Code Playgroud)
函数和别名通常是为了方便或添加补充功能.
shell脚本怎么样?...命令行fork()一个新进程和exec()这个脚本在新进程中?然后这个新进程会包含脚本fork()其他进程来执行date,cc编译器等吗?
是的,完全正确.运行shell脚本时,父shell会分叉子进程,并且脚本在那里运行.脚本中的命令因此分离出这个子进程; 他们是原壳的孙子.