Linux Bash/Shell是如何读取并处理用户输入的命令的?
Bash 解析命令严格遵循从左到右逐字符扫描的规则,不存在两端向中间读取的逻辑,整个解析流程有固定的分步规则,以下是详细说明:
通用解析分步流程
- 第一步:输入读取与初步分词
Bash 从左到右逐个读取输入字符,先根据元字符(空格、制表符、换行、;()<>|&等)把输入拆成多个标记(token),同时识别引号、转义符的边界,如果遇到未闭合的引号会触发继续读取输入的逻辑。 - 第二步:别名展开
如果第一个token没有被引号包裹,会先检查是否为已定义的别名,匹配成功则替换为别名对应的内容,回到第一步重新扫描替换后的内容(仅当别名定义末尾带空格时,才会继续对下一个token做别名检查)。 - 第三步:花括号展开
对{a,b,c}、{1..10}这类花括号语法做展开,生成多个并列的token。 - 第四步:波浪号展开
把~替换为当前用户家目录,~用户名替换为对应用户的家目录。 - 第五步:参数/变量展开
识别$开头的变量、${}格式的变量表达式,将变量替换为对应的实际值,无特殊设置的空变量会直接替换为空字符串。 - 第六步:命令替换
识别`命令`和$(命令)格式的表达式,执行内嵌的命令,把输出结果替换到原位置。 - 第七步:算术展开
识别$((算术表达式))的内容,计算算术结果替换到原位置。 - 第八步:单词拆分
对前面步骤展开后生成的、未被引号包裹的部分,按照IFS(内部字段分隔符,默认是空格、制表符、换行)再次拆分出多个token,连续的IFS字符会被当作单个分隔符处理。 - 第九步:路径名展开
对包含*?[]这类通配符的token,匹配对应的文件路径,把匹配到的所有路径替换为对应的token列表。 - 第十步:命令查找与执行
把第一个token当作要执行的命令,按别名、内置命令、$PATH路径下可执行文件的顺序查找匹配,剩余token作为参数传递给命令执行。
示例
bash -c " echo "$S" "的逐流程解析 我们假设当前环境下变量S的赋值为test,方便演示解析效果:
- 初步从左到右扫描拆分token:第一个token是
bash,第二个是-c;接下来遇到第一个双引号",开始收集字符串直到下一个双引号,得到内容echo(前后带空格)作为第三个token;接下来的$S是未被引号包裹的变量表达式,第四个token暂定为$S;随后遇到第三个双引号,收集内容直到第四个双引号,得到内容(单个空格)作为第五个token。
注意这里的常见误区:你写的
" echo "$S" "实际是三个字符串的拼接:前面的" echo "+ 中间无引号包裹的$S+ 后面的" ",因为双引号是从左到右两两闭合的,不会自动匹配外层的引号。
- 别名展开:
bash不是别名,跳过该步骤。 - 花括号、波浪号展开:无对应语法,跳过。
- 变量展开:把
$S替换为实际值test。 - 命令替换、算术展开:无对应语法,跳过。
- 单词拆分:
$S替换后的值test没有包含IFS字符,拆分后仍为单个tokentest。 - 路径名展开:无通配符,跳过。
- 最终生成的参数列表为:
bash、-c、echo、test、 - 执行命令:调用bash程序,
-c参数后的第一个参数是要执行的脚本内容也就是echo,后续的test和空格会被当作子bash的$0和$1位置参数,最终子bash仅执行echo输出空行,并不会打印test的值,这就是嵌套引号写法错误的典型表现。
内容的提问来源于stack exchange,提问作者tmp
相关产品推荐
相关产品推荐

