概述
一些shell 编程中的总结,希望能帮到后面的朋友,少点学习成本
若有错误,欢迎指正
脚本执行
在当前shell 中执行
- source test.sh
- . test.sh
- 开一个子shell 执行
- bash test.sh
- ./ test.sh
引申:当在一个脚本中需要用到外部脚本的变量的值,使用source 或 .
设置变量的3种方法
- export 变量名=value (等号两边无空格)
- 变量名=value ; export 变量名
- declare -x 变量名=value
单引号(' ')和双引号(" ")的区别
- 单引号( ' ' ):强引用,里面的变量值原样输出
- 双引号( " " ):弱引用,变量会转换为相应的值
变量输出两种方法
- $a
- ${a}
引申${a}: a=xxx
${a}_test --输出--> xxx_test
脚本里引用linux命令
- CMD=`ls` 反引号(tab键上面的点)
- CMD=$(ls) $()
小结: 数字变量的定义 不加双引号( " " )
其他的时候加双引号( " " )
原样输出加单引号( " " )
引申: awk 使用:正确的输出变量值
TT="test"
- awk ‘BEGIN {print " 'TT' "}’ TT 这个变量单引号外部再加一个双引号
- echo "$TT" | awk '{print $0}' 通过echo 和管道的方式
变量名赋值,两边不能有空格
- a=1 正确
- a = 1 错误
shell 中特殊且重要的变量
- $0: 获取执行脚本的文件名
- $n:获取脚本中第n个参数,n>9 ,${10}
- $#: 获取执行shell 后参数的总个数
- $*: 获取当前脚本所有传参参数,不加引号相当于 $@
- $@: 不加引号与$*一样
- $?: 获取上一个指令执行状态码 (0 成功,非零失败)
- $$:获取当前执行shell脚本中的PID
加引号后的 $* 和 $@区别
- "$@" ---> "$1 $2 $3..."
- "$*" ----> " $1" "$2" "$3" ...
shell 脚本条件测试与比较
- test <condition>
- [ <conditon> ] :linux 里的脚本大多数使用的这种,建议使用这种方式
- [[ <conditon> ]]
- ((<condtion>)) :双括号一般用于if语句,两边不需要空格
1. test -f file && echo true || echo false
2. [ -f file ] && echo true || echo false
1和2 完全等价,注意2 [ ] 两边的空格
- && || > < ... 用于 [[ ]]
- -a -0 -gt -lt ...用于 [ ]
- [ ] 测试变量要加" " ---> [ -f "$file" ] && echo true || echo false 不能是 $file 要加双引号
[ ] 用法延伸:
[ <conditon> ] &&{
cmd1
cmd2
cmd3
}
if [ conditon ]
then
cmd1
cmd2
fi
常用的文件测试操作符
-d | direction | 存在为真 |
-f | file | 存在为真 |
-e | exist | 存在为真 |
-r | read | 存在为真 |
-s | size | 存在且大小不为0 |
-w | write | 存在为真 |
-x | exceutable | 存在为真 |
-L | link | 存在为真 |
file1 -nt file2 | newer than | 文件f1比f2新则真,文件修改时间来判断的 |
file1 -ot file2 | older than |
字符串测试
- -n "str" 长度不为0为真, no zero
- -z "str" 长度为0 为真 zero
- "str1" = "str2" str1 等于str2 为真 = 可以换成 ==
- "str1" != "str2" str1 不等于str2 为真
= != 两边有空格 ,=两边没有空格是赋值操作噢
字符串截取操作
格式 | 说明 |
${string: start :length} | 从 string 字符串的左边第 start 个字符开始,向右截取 length 个字符。 |
${string: start} | 从 string 字符串的左边第 start 个字符开始截取,直到最后。 |
${string: 0-start :length} | 从 string 字符串的右边第 start 个字符开始,向右截取 length 个字符。 |
${string: 0-start} | 从 string 字符串的右边第 start 个字符开始截取,直到最后。 |
${string#*chars} | 从 string 字符串第一次出现 *chars 的位置开始,截取 *chars 右边的所有字符。 |
${string##*chars} | 从 string 字符串最后一次出现 *chars 的位置开始,截取 *chars 右边的所有字符。 |
${string%*chars} | 从 string 字符串第一次出现 *chars 的位置开始,截取 *chars 左边的所有字符。 |
${string%%*chars} | 从 string 字符串最后一次出现 *chars 的位置开始,截取 *chars 左边的所有字符。 |
整数二元比较
[ ] test使用 | (()) [[ ]] | 说明 |
-eq | == or = | equal |
-ne | != | not equal |
-gt | > | greater than |
-ge | >= | geater equal |
-lt | < | less than |
-le | <= | less equal |
注意:比较两端要有空格
[[ ]] 使用: 除非在[ ] 无法满足需求时使用,特殊正则匹配等。。。
推荐使用 [ ] ,-eq 这种方式,linux shell 这种方式用的比较多 -。-
逻辑运算符
[] test | [[ ]] (( )) | 说明 |
-a | && | and |
-o | || | or |
! | ! | not |
"&&" "||" 可用于[[ ]] 和(( ))中,也可以连接多个 [ ]
[[ ]] 大多数用于通配符的场景
if [[ "$test" == /dev/test* ]] -----> 这种情况[ ] 不支持
测试表达式小结
符号 | [ ] | test | [[ ]] | (( )) |
边界两端需要空格 | yes | yes | yes | no |
逻辑操作符 | -a -o ! | -a -o ! | && || ! | && || ! |
整数比较 | -eq -gt... | -eq ... | -eq > .. | = > .. |
字符串比较 | = == != | = == != | = == != | = == != |
支持通配符比较 | no | no | yes | no |
shell if 语句规则
if <condition> ;then
fi
---------------------
if <condition>
then
xxx
elif <condition> ;then
xxx
else
xxx
fi
--
case 语句
case "变量" in
值1)
指令1
;;
值2)
指令3
;;
*)
指令3
esac
while 语句
while <条件表达式>
do
指令
done
until 语句
until <条件表达式> 条件不成立时进入循环,与while 相对 用的少
do
指令
done
select 语句
select 变量名 [ 菜单取值列表]
do
指令
done
for 语句
for 变量名 in 变量值列表 ---->变量名列表可以省略,省略后相当于 in "$@"
do
指令
done
for ((exp1;exp2;exp3))
do
指令
done
shell 函数语法
function 函数名() {
return n
}
function 可以去掉, 建议不去掉
调用 :
函数名
函数几个注意点:(如果你懂其他语言可忽略)
return 退出函数,返回值给调用此函数的程序
exit 退出脚本,返回值给当前shell
函数放在独立的文件中,可以通过source " . " 来加载
/etc/init.d/function linux 内置的脚本函数库
shell 脚本中
main $* ---> 把命令行接收的所有参数作为函数参数 传给函数内部 常用的手法
脚本中判断一个程序是否起来,转换成数字比较
判断 mysql 是否起来
[ `netstat -lntup | grep mysql | wc -l` -gt 0 ] 把端口转化为数字比较
shell 数组
- array=(value1 value2 value3 ...) 值之间没有逗号
- array([1]=one [2]=two [3]=three)
- array=(`command`)
删除数组
- unset array[i] --> 删除指定
- unset array --> 删除整个数组
数组截取
array=(1 2 3 4 5)
echo ${array[@]:1:3} 截取 1-3号数组 --->out : 2 3 4
小结:
man bash 搜索 arrays 了解
静态数组: array=(1 2 3 4 5)
动态数组:array=($(命令)) array=($(ls))
赋值: array[3]=4
打印 :
- 答应数组里的元素 ${array[@]} ${array[*]}
- 数组长度 ${#array[@]} ${#array[*]}
- 单个元素 ${array[i]} i是数组下标
shell 脚本调试
shell [-nvx] xxx.sh
- -n:不执行脚本,检查脚本语法问题
- -v:先输出脚本,再执行
- -x:显示脚本执行过程
脚本中 调试脚本部分内容
- set -x
- set +x
echo 语句大法好-。-
后台执行脚本方法
- sh test.sh &
- nohup test.sh &
- screen 保持会话,执行命令 or 脚本
子shell问题
-
& 可异步
-
管道 | 不可异步
-
脚本中用"( )" 功能调用 外部shell 不可异步
-
子shell 可以获取父shell 变量值, 反之不行
-
source " . " 不会再shell 中开子shell
shell 脚本中用 fork source exec 执行其他脚本的区别
- 一般使用的bash xxx.sh 就是用的fork模式(儿子的环境变量不会影响父亲的环境,执行完了儿子,继续执行父亲的命令)
- 如果想让父进程得到子进程的环境变量用 source (儿子的环境变量会影响父亲的环境,执行完儿子,继续做父亲的事)
- exec 等同于source 只是exec 行以后的代码不会执行了(儿子的环境会影响父亲的环境,执行完儿子,退出,不做父亲后面的事)