1. 执行命令
基本有约定:shell脚本一般以.sh结尾,也可以没有;脚本文件第一行用来指定用什么解释器来执行:
#! /bin/bash
启动方式:
- 文件名运行: ./filename.sh
- 解释器运行: bash filename.sh
- source运行: source filename.sh
2. 执行流程
从图中可知,shell脚本的执行过程包括字符解析、shell展开、重定向、执行命令(builtin)、子进程执行命令(非builtin)、状态返回等过程。可能涉及用户态到内核态到转换。
2.1 字符解析
-
识别换行符、分号,做行的分割;
-
识别命令连接符(||、&&、|),做命令的分割;
-
识别空格、tab符,做命令和参数的分割。
2.2 shell展开
- 大括号展开
一般由三部分(前缀、大括号、后缀)组成,大括号内可以是逗号分隔的字符串,也可以是序列表达式{x..y[..incr]};
# 字符串list
a{b,c,d}e => abe ace ade
#序列表达式
{1..5} => 1 2 3 4 5
{1..5..2} => 1 3 5
{a..e} => a b c d e
- 波浪号展开 波浪号展开为用户的主目录:
#当前用户
~ => $HOME
#指定用户
~king => king用户的$HOME
- 参数展开 ${}
(1) 间接参数扩展 间接参数扩展相当于将参数进一步展开:
parameter="var"
var="hello"
echo ${!parameter}
# 此时输出 hello, 也就是var的值
(2) 参数长度
${#parmeter} 使用#可以获取参数的长度
(3) 空参数处理 ${parameter:-word} : 如果parameter为空则替换为word
${parameter:=word} : 如果parameter为空则替换为word,且将parameter赋值为word
${parameter:?word} : 为空报错
${parameter:+word} : 如果parameter不为空,则将parameter替换为word
(4) 参数切片
${parameter:offset} : 从offset到最后
${parameter:offset:leghth} : 从offset开始取length个字符
- 命令展开
在子进程中执行命令,并用得到结果返回,使用$()或``的方式:
echo $(whoimi) #在子进程中执行whoimi命令
function(){
echo "function"
}
result=`function` #在子进程中执行function函数
- 数学计算
使用$(())进行数学计算
echo $((1+2)) ---> 3
- 文件名展开
当有单词没有被引号包裹,且其中出现了'*'、'?'、或‘[’字符,则shell会去按照正则匹配的方式查找文件名进行替换,如果没找到则保持不变:
echo D*
输出当前目录下所有以D字母开头的目录、文件
2.3 重定向
将stdin、stdout、stderr的文件描述符进行指向变更:
- 输出重定向
> : 覆盖写入文件 >> : 追加写入文件 &> : 标准输出和错误输出统一写入文件 2> : 错误输出写入文件
- 输入重定向
< : 重点向标准输入 << : 沿用标准输入,当识别到指定标识符(如EOF)后停止,将收到的内容作为stdin
2.4 命令执行
-
builtin命令直接执行
-
非内置命令查找$PATH后启动子进程执行