当我运行命令时,例如test -l --hello check
:
shell将命令保存到变量,$0="test"
shell执行 相应的二进制文件$1="-l"
二进制 文件读取变量 二进制文件执行变量所说的操作$2="--hello"
$3="check"
标准流只是这些变量吗?
对@philip-couling 的问题(我在这里问是因为评论有限):
我认为您想询问重定向运算符和管道:<、>、|。
是的,标准流这就是重定向和管道的工作原理,对吧?
将文本行分解为参数
它保存参数/标志以及命令本身。例如,ls 是命令部分,-la 是参数部分。这很重要,例如,对于busybox来说,它只是一个二进制文件,并且通常使用符号链接调用(如果您运行例如/bin/ls(在路径so ls中),它是到/bin/busybox的符号链接,busybox二进制文件需要一种方法来知道命令及其标志)。
作为数组传递给命令
作为数组?它不使用 $0..$∞ 变量?
当您打开文件进行读取或写入时,操作系统会为您提供一个“文件描述符”,它只是一个数字。子进程从其父进程继承文件描述符。在父级中打开的任何文件也将打开并可供子级使用(除非文件是在明确指示不打开的情况下打开的)。
每个文件描述符只是一个数字。前三个用于 stdin(0) stdout(1) stderr(2)。请参阅 posix 中的 STDERR_FILENO。据我所知,这些在技术上并不是保留的,但事实上这三个描述符通常存在,防止其他人使用相同的号码。
软件语言可能有特殊的语法来写入标准输出(如 echo 或 print),但实际上二进制文件所做的只是写入文件描述符编号 0。
哦,现在我记得文件描述符和 stdin、stdout、stderr 是 0、1、2。对这些的解释真的很好!但问题是,命令的所有输出都转到 1 和 2,对吧?那么,1和2什么时候会被清除呢?
答案1
我认为您想询问重定向运算符和管道:<
, >
, |
。
对于命令行参数,shell 会将文本行分解为参数,以数组形式传递给命令。 shell 调用fork
创建一个新进程,然后用于exec
启动新命令并传递参数。
对于重定向来说,情况有点复杂。文件名不直接传递。相反,标准流是从父进程继承的,shell 必须在fork
和之间修改它们exec
。
当您打开文件进行读取或写入时,操作系统会为您提供一个“文件描述符”,它只是一个数字。子进程从其父进程继承文件描述符。在父级中打开的任何文件也将打开并可供子级使用(除非文件是在明确指示不打开的情况下打开的)。
每个文件描述符只是一个数字。前三个用于 stdin(0) stdout(1) stderr(2)。看STDERR_FILENO在 posix 中。据我所知,这些在技术上并不是保留的,但事实上这三个描述符通常存在,防止其他人使用相同的号码。
软件语言可能有特殊的语法来写入标准输出(如echo
或print
),但实际上二进制文件所做的只是写入文件描述符编号 0。
重定向运算符的工作方式是,shell 打开文件或创建一个管道来获取文件描述符,然后调用dup2
将描述符复制到三个 (0,1,2) 之一,然后再调用exec
.
因此子进程永远不会被告知它在 stdin、stdout 或 stderr 上打开了什么。它只有文件描述符,如果它询问操作系统,它可能能够获得更多信息。