1.变量替换及应用
${var:-word} 如果var存在且非空,则返回var,否则返回word但是不替换var
${var:+word} 如果var存在且非空,则返回word(不替换var),否则返回var
${var:=word} 如果var存在或为空,则返回var,否则返回word且替换var
${var:?message} 如果var存在且非空,返回var,否则返回"var:message"这个字符串
${var:offset} 在var中提从offset到其末尾的子字符串
${var:offset:length} 在var中从offset开始提取length长的子字符串
${var#pattern} 返回删除掉var中开头pattern最短匹配后剩余的字符串
${var##pattern} 返回删除掉var中开头pattern最长匹配后剩余的字符串
${var%pattern} 返回删除掉var中结尾pattern最短匹配后剩余的字符串
${var%%pattern} 返回删除掉var中结尾pattern最长匹配后剩余的字符串
${var/pattern/string} 用string替换var中开头pattern的最短匹配
${var//pattern/string} 用string替换var中开头pattern的最长匹配
例子:
${*:-.} 如果没有提供位置参数则使用当前目录
${path##*/} 从全路径中获取基本文件名,等价于basename(外部程序没shell内置机制效率高)
${path%/*} 获取目录名,等价于dirname(外部程序没shell内置机制效率高)
2.命令替换及应用
$(command)
`command`
ROOT=`pwd` <=> ROOT=$(pwd)
3.数学运算
let i=i+1 bash 内置变量(不能加空格)
((i += 2)) 运算符可用空格隔开
i=`expr 3 \* 5` 注意需要转义符
i=$(expr 3 \* 5)
i=`echo "scale=2; $TSIZE/$SSIZE*100" | bc -l` bc命令不一定每个linux用户都安装了
declare -i a=1 b=2;declare c=a+b 声明称整数来计算
4.数组及应用
数组初始化:
var[index]=value 整数做下标
var[string]=value 字符串做下标
var=(value1 value2 ...) 空格隔开
清空数组:
var=
unset var
unset var[value]
引用数组数据:
${var} 引用不带下标的数组,得到数组第一个元素
${var[variable]} 下标使用变量时不需要美元符号引用
${var[@]} 得到数组所有元素
${var[*]} 得到数组所有元素
${#var[@]} 得到数组元素个数
${#var[*]} 得到数组元素个数
5.特殊变量
$$ 当前shell的PID
$! 在后台运行的最后一个作业的PID
$? 关于上个执行指令的回传码
$0 当前shell的名字
$n (n:1-) 位置参数
$# 参数个数
$* 所有位置参数组成的单一字符串
$@ 每个位置参数的字符串组合成的
$*和$@的区别
$*将所有位置参数作为单一字符串
$@是所有位置参数的字符串组合
function "$*" 函数参数只有一个
function "$@" 函数参数有多个
6.命令行选项
通常使用getopts,第一个冒号表示用户键入错误选项时不提示
$OPTARG表示选项对应的参数值,$OPTIND表示命令行选项的索引
模板:
while getopts ":X1:X2:..." opt;do
case $opt in
x1) value_x1=$OPTARG;;
X2) ..;;
esac
done
shift $(($OPTIND-1))
7.命令行解析
一个shell命令行的完整处理过程:
1).将输入分隔成记号(记号包括单词,关键字,I/O定向符,分号等)
2).检测每个命令的第一个记号,若为开发关键字(像if等)则继续匹配一个完整的符合命令,重复处理完成,返回步骤1。
3).别名检测(检测第一个记号是别名就进行替换,返回步骤1)
4).大括号扩展(a{b,c}扩展为ab ac)
5).~符号扩展(如果存在替换为$HOME)
6).变量(参数)替换(以$开头的表达式)
7).命令替换(对$(string)形式进行)
8).算术替换(对$((string))进行计算)
9).单词分隔(使用$IFS中的字符分隔参数,命令,算术替换中的部分成单词)
10).路径名扩展(通配符扩展,例如*,/等)
11).命令查询(函数>内置命令>脚本和可执行程序)
12).运行命令(设置完I/O重定向后执行命令)
单引号‘’(绕过前10个步骤)
单引号中的命令只能执行路径扩展,命令查找
双引号""(绕过步骤1~5,9,10)
双引号中可以使用参数替换,命令替换,算术替换
命令查找顺序可以用command,builtin,enable来修改
command删除别名和函数查找
builtin只查找内置命令
enable -a显示所有命令及其是否可用
eval通知shell接受eval参数,并再次通过命令行处理的所有步骤来运行
所以被绕过的步骤可以重新解析
shell解析命令顺序
别名>关键字>函数>内置命令>脚本和可执行程序
8.进程控制
作业编号指当前运行在用户shell下的后台进程(不同shell窗口下的作业毫无关系)
进程ID指当前运行在整个系统上的所有用户的进程
作业控制:
jobs -l列出作业的完整信息
引用后台作业的方式:
fg %N 作业编号N
fg %string 作业命令名以string开始的作业
fg %?string 作业命令包含的string的作业
fg %+ 最近被调用的后台作业(引用被放到后台的最新作业)
fg %% 同上
fg %- 第二个最近被调用的后台作业
fg (不带%) 作业进程ID
使用的作业控制的好处:
有可能前台的作业运行时间很长,而你还想用控制终端做其他操作,这是就可以将其放到后台
CTRL-Z即将当前作业放到后台
kill用法:
kill参数可以使进程ID,作业编号,进程命令名
kill默认发送TERM信号到目标,但可以改变所发信号类型
kill -l 列出支持的所有信号名称和编号列表
CTRL-C INIT
CTRL-\ QUIT
CTRL-Z TSTP
kill TERM
stty signame char可以绑定信号到什么控制键上 例如:stty intr ^X
kill %作业编号
kill 进程ID
kill 进程名
kill 信号类型 参数
协同程序:
shell命令行下协同,执行命令之间使用&即可
脚本里面,最后必须加上wait命令保证所有后台作业都完成
模式:
命令1 &
...
命令2
wait
进程使用系统资源的特性:CPU密集型,I/O密集型,交互式
对于I/O密集型使用一个大型计算的作用会较好
对于CPU密集型,多通过shell并发执行回提高效率
当在一个多CPU计算机上启动一个后台作业时,计算机会将其赋予到下一个可用处理器
这意味着两个作业时间上运行在同一时刻,所有能提升效率
子shell:
子shell继承的东西:
1)当前目录
2)环境变量
3)标准输入,标准输出,标准错误,以及其他任何打开的文件描述符
4)被忽略的信号(trap)
未继承的东东:
1)shell变量(除了环境变量和定义在环境文件中.bashrc的变量)
2)没被忽略的信号处理
exec精髓,替换本shell来执行exec参数中的命令对本shell一直发生影响
exec 2>errlog 把脚本中所有错误写到errlog文件中(放在脚本开头)
exec switch_root /newroot "/sbin/init" 启动脚本中常常见到