一直相对shell脚本进行系统性学习,由于时间的原因,每次都是看一点,过一段时间又忘了,这次狠下心做一次shell script的学习和分享,和大家一起掌握好shell,下面先大体描述下技术层面的shell,后面主要就是练习。
首先什么是shell script呢?它是利用shell的功能所写出来的一个程序,这个程序是使用纯文本文件,将一些shell提供的命令写在里面,再搭配正则表达式、管线、数据流导向等功能,以达到我们想要处理的目的。
那script的执行方式有哪些,它们之间又有什么区别?一共三种分别是./script、sh script以及source script。
在执行./script、sh script时,该脚本都会使用一个子程序(新的bash)环境来执行脚本内的命令,当子程序完成后,在子程序内的各种变量或动作将会结束而不会传回父程序中,即你在子程序中声明的变量,在父程序中是使用不了的。
而在执行source script时,脚本是在父进程中执行的,所有脚本执行完,其中的变量还是能继续使用。
下面主要就是实战:
一、善用判断:
1、test:
2、利用判断符号[]:[ "${name}" == "name" -o "${name}" == "Name" ]
数字的比较:
-eq 相等(equal)
-ne 不等(not equal)
-gt 大于(greater than)
-lt 小于(less than)
-ge 大于等于 (greater than or equal)
-le 小于等于 (less than or equal)
字符串的比较:
[ $str1
= $str2
] 等于
[ $str1
!= $str2
] 不等于
[ -z $str
] 空字符串返回true
[ -n $str
] 或者 [ $str
] 非空字符串返回true
a、在[]中的每一个组件都需要有空格键来分隔
b、在[]里的所有变量最好都以双引号括号起来
c、在[]里的所有常量最好都以单/双引号括号起来---这里建议一样使用双引号
3、默认变量:$0、$1等
a、$#:代表参数的个数
b、$@:将所有变量用引号括起来,即'opt1 opt2 opt3 opt4'
对于$str代表什么意思可以参考:https://www.cnblogs.com/kaituorensheng/p/4002697.html
4、shift造成变量偏移:
当script中执行过shift后,$@:将所有变量用引号括起来,即'opt2 opt3 opt4'
5、if....then:
句式:
if [ 条件一 ];then
elif [ 条件二 ];then
else
fi
&&代表AND
||代表or
[ "${yn}" == "y" or "${yn}" == "Y" ] 和 [ "${yn}" == "y" ] || [ "${yn}" == "Y" ]
6、利用case......esac:
7、循环
a、while [ 条件 ]
do
pass
done
b、for var in con1 con2 con3
do
pass
done
c、for (( 初始值;限制值;执行步骤))
do
pass
done
二、xargs、awk和sed
1、xargs:
之所以能用到这个命令,关键是由于很多命令不支持|管道来传递参数,而日常工作中有有这个必要,所以就有了xargs命令,然后将管道中的输出,每一行执行以下后面的命令,如果后面没有命令,默认echo
下面主要了解下相关参数:
-d:默认情况下xargs将其标准输入中的内容以空白(包括空格、Tab、回车换行等)分割成多个之后当作命令行参数传递给其后面的命令,并运行之,我们可以使用 -d 命令指定分隔符
例:echo '11@22@33' | xargs -d '@' echo
输出: 11 22 33
-n:该选项表示将xargs生成的命令行参数,每次传递几个参数给其后面的命令执行,例如如果xargs从标准输入中读入内容,然后以分隔符分割之后生成的命令行参数有10个,使用 -n 3 之后表示一次传递给xargs后面的命令是3个参数,因为一共有10个参数,所以要执行4次,才能将参数用完。
例:echo '11@22@33@44@55@66@77@88@99@00' | xargs -d '@' -n 3 echo
输出:11 22 33
44 55 66
77 88 99
00
-E:该选项指定一个字符串,当xargs解析出多个命令行参数的时候,如果搜索到-e指定的命令行参数,则只会将-e指定的命令行参数之前的参数(不包括-e指定的这个参数)传递给xargs后面的命令
例:echo '11 22 33' | xargs -E '33' echo
输出:11 22
2、sed
sed命令是一个面向字符流的非交互式编辑器,也就是说sed不允许用户与它进行交互操作。sed是按行来处理文本内容的。在shell中,使用sed来批量修改文本内容是非常方便的。
3、awk https://www.cnblogs.com/xudong-bupt/p/3721210.html
相比较屏幕处理的优点,在处理庞大文件时不会出现内存溢出或是处理缓慢的问题,通常用来格式化文本信息,依次对每一行进行处理,然后输出
awk [-F|-f|-v] ‘BEGIN{} //{command1; command2} END{}’ file
[-F|-f|-v] 大参数,-F指定分隔符,-f调用脚本,-v定义变量 var=value
' ' 引用代码块
BEGIN 初始化代码块,在对每一行进行处理之前,初始化代码,主要是引用全局变量,设置FS分隔符
// 匹配代码块,可以是字符串或正则表达式
{} 命令代码块,包含一条或多条命令
; 多条命令使用分号分隔
END 结尾代码块,在对每一行进行处理之后再执行的代码块,主要是进行最终计算或输出结尾摘要信息
特殊要点:
$0 表示整个当前行
$1 每行第一个字段
NF 字段数量变量
NR 每行的记录号,多文件记录递增
FNR 与NR类似,不过多文件记录不递增,每个文件都从1开始
\t 制表符
\n 换行符
FS BEGIN时定义分隔符
RS 输入的记录分隔符, 默认为换行符(即文本是按一行一行输入)
~ 匹配,与==相比不是精确比较
!~ 不匹配,不精确比较
== 等于,必须全部相等,精确比较
!= 不等于,精确比较
&& 逻辑与
|| 逻辑或
+ 匹配时表示1个或1个以上
/[0-9][0-9]+/ 两个或两个以上数字
/[0-9][0-9]*/ 一个或一个以上数字
FILENAME 文件名
OFS 输出字段分隔符, 默认也是空格,可以改为制表符等
ORS 输出的记录分隔符,默认为换行符,即处理结果也是一行一行输出到屏幕
-F'[:#/]' 定义三个分隔符
三、上述都是系统的讲述了些编写shell script的方法,下面主要介绍些常用的知识点:
1、获取变量长度:${#variable}
2、${variable:-10}
和 ${variable: -10}
有什么区别?
${variable:-10}
- 如果之前没有给 variable 赋值则输出 10;如果有赋值则输出该变量${variable: -10}
- 输出 variable 的最后 10 个字符
3、set -e :在"set -e"之后出现的代码,一旦出现了返回值非零,整个脚本就会立即退出
4、如果mano.conf文件中的内容为
version1=1
version2=2
那么source mano.conf后$version1的值就是1,$version2的值就是2
四、数组
一、常用数组:
一般将数组分为两种数值类型,一是数值类型,二是字符串类型
表现形式为arr_number=(1 2 3 4 5);arr_string=("abc" "edf" "sss");
常用的集中操作:
- 获取数组长度:
arr_length=${#arr_number[*]}或${#arr_number[@]}均可,即形式:${#数组名[@/*]} 可得到数组的长度。
- 读取下标的值:
arr_index2=${arr_number[2]},即形式:${数组名[下标]}
- 对对应下标进行赋值:
- 如果该下标元素已经存在,会修改该下标的值为新的指定值
arr_number[2]=100,数组被修改为(1 2 100 4 5)
- 如果下标已经超过当前数组的大小,新赋的值被追加到数组的尾部。
arr_number[13]=13,数组被修改为(1 2 100 4 5 13)
- 删除操作:
- 清除某个元素:unset arr_number[1],这里清除下标为1的数组;
- 清空整个数组:unset arr_number;
- 分片访问:
分片访问形式为:${数组名[@或*]:开始下标:结束下标},注意,不包括结束下标元素的值。
例如:${arr_number[@]:1:4},这里分片访问从下标为1开始,元素个数为4。
- 遍历:
- 遍历值:
for v in ${arr_number[@]}; do
echo $v;
done
- 遍历下标:
for i in ${!arr_number[@]}; do
echo $i , ${arr_number[$i]};
done
注:bash里面数组的下标,不是位置的偏移,而是具体的值,就像map的key一样;后面我们看到关联数组使用字符串作为下标。所以从for v in ${arr_number[@]}; do里面取出的值对应的下标不一定是0,1,2....要先顺序显示可以使用:
length = ${#arr_number[*]}
for index in `seq ${length}`
do
echo ${arr_number[$index ]}
done
- 关联数组:
关联数组的索引可以是字符串,使用关联数组之前必须先声明关联数组。
声明关联数组:
declare -A ass_array
基本操作:
1、赋值:
A) 列表发赋值
ass_array=( [index1]=val1 [index2]=val2)
- 单独赋值
ass_array[index1]=val1
ass_array[index2]=val2
其它操作和常用数组一样:
2、查询关联数组所有元素内容:
echo ${ass_array[*]}
3、查询关联数组的索引:
echo ${!ass_array[*]}
4、查询关联数组的元素个数:
echo ${#ass_array[*]}
例子:关联数组(字典)操作:
#!/bin/bash
#必须先声明
declare -A dic
dic=()
while read line
do
array=(${line//,/ })
for var in ${array[@]}
do
let dic[$var]=${dic[$var]}+1
done
done < words.txt #如果放在前面dic[$var]就变成局部变量后续输出不了值
out_put=""
for key in ${!dic[*]}
do
out_put=${out_put}`echo "$key ${dic[$key]}_"`
done
echo ${out_put%?} | tr '_' '\n' | sort -n -r -k 2
#!/b