目录
看完第十二章发现其实脚本的编写总体有C的影子,但是也有python的灵活性,以及大量比较好用的命令,所以学会脚本编写是大有裨益的。其中,对于数据流的处理很多,所以先将前面遇到的grep等数据处理工具进行一个总结。
1 grep、cut、awk、sed对比总结
命令 | 能否正则 | 处理对象/功能 | 格式 | 常用参数 | 例子 |
cut | 否 | 行中切出一段信息 | cut -d '分割字符' -f field field:指被分割的第几段 | -c:以字符为单位取 -d:分割字符 -f:后跟第几段 | echo ${PATH} | cut -d ':' -f 3,5 取出PATH的第三和五个路径 |
grep | 可,且egrep可扩展正则 | 找到所需要信息的行 | grep [ ] '查找字符' filename | -c:计算查找到次数 -i:忽略大小写 -v:反向选择 -n:顺便输出行号 -A:可跟数字,后面几行也输出 -B:可跟数字,前面几行也输出 | grep -n ‘t[ae]st’ reg.txt 查找tast或者test的行 egrep -v '^$|^#' reg.txt 去除空白行和以#为行首的行 |
sed | 可且扩展 | 替换/删除/新增/选取行,或者替换一段信息 | sed [ ] [ ‘[n1[, n2] function ’ ] n1 n2 代表行数 function需要被 ' ' 括住,有: a:下一行新增 c:替换 d:删除 i:插入 p:打印 s:替换 s/被替换/新的字符/g | -n:只输出处理过的行 -e:命令行模式操作 -f:将sed写入文件 -f filenaem:执行filename文件内的sed -r:使用扩展正则 -i:直接修改不输出到屏幕
| sed '2a drink tea' 第二行下加上drink tea sed ‘2,5 no number’ 第二到五行替换成no number sed ‘s/#.*$//g' 将#开头的行替换成空行 sed ' /^$/d' 删除空白行 /删除字符/d |
awk | 可 | 行中信息分段处理 | awk ‘条件1{操作1} 条件2 {操作2} ...’ filename
| 内置变量: NF: 每一行字段总数 NR:目前处理第几行 FS:目前分割字符,默认空格 $0:代表一行 $1 $2 ...:变量形式代表第几个字段 条件: 可以用逻辑运算符 | awk ‘ $3<10 {print $1 "\t" $3}’ 若第三字段小于10则将第一字段和第三字段列表出来 awk ‘BEGIN {FS=':'} $3 <10 {print $1 "\t" $3}’ 将分割符换成:,同上 注意print 和printf不一样 |
2 脚本的一些重要语句
脚本的参数,是直接在执行脚本时传入的,如 sh a.sh 参数1 参数2 ... 在脚本中以$1 $2 .. 的形式使用
2.1 判断式test与[ ]
判断命令可以用test或者[ ]。test 可以直接跟例如-e -f 加上文件名,来判断是否存在或者是否为文件,而[ ]则相当于代理了test,语法基本一致,只有小小的格式需要注意:[□-e 文件名□],即[ ] 两边是要加空格(用□表示)的。
推荐使用[ ],句法简单易于读。
为了方便将鸟叔中书上部分参数拍下,如下
2.2 if语句
if [ 条件判断式 ]; then
语句块
fi
if [ 条件判断式 ]; then
语句块
elif [ ]; then
语句块
fi
if [ 条件判断式 ]; then
语句块
else
语句块
fi
注意:变量和字符串比较需要用 “${变量}” == “字符串” 即两边都需要“ ”括起来。
2.3 case语句
case $变量 in
"第一个变量内容")
语句块
;;
"第二个变量内容")
语句块
;;
*)
语句块
;;
esac
case用法和C的switch一样,但需要注意语法
- 选择的变量内容后只有 )
- 每个块需要;;结束,有些像break
- 最后一个是*) 匹配所有字符 有些像 default
2.4 循环 while、until、for
while [ 条件 ] #当成立开始循环
do
语句块
done
until [ 条件 ] #当成立结束循环
do
语句块
done
for 变量 in con1 con2 ... #有些像python中直接把后面的量赋给变量,而且只要有空格隔开
do #所以可以类似 for username in ${usrs} user中有很多空格隔开的名字
语句块 #注意:变量前是没有$的
done
for ((初始值;限制值;赋值运算)) #这个和C的基本一样,只不过是两层括号
do
语句块
done
2.5 函数
function fname() { #和C一样
语句块
}
#调用:
fname 参数1 参数2 ...
#在函数体中表示 参数1:$1 参数2:$2 ...
这里参数记得与脚本的参数区别,用C++来看,函数的作用域在脚本作用域中,所以在函数体中,函数的$1会将脚本的$1隐藏。
2.6 脚本调试
- source:在父进程中执行,所以可以用来更改改变系统设置
- sh:在子进程中执行
sh [ ] 脚本文件
-n:仅检查语法问题
-v:执行前先将脚本内容输出到屏幕
-x:将使用的脚本内容输出到屏幕,可以用来调试
部分习题自做答案
第一题:
#!/bin/bash
#Program:
# chapter12 first exercise.
#History:
# 2023/02/06
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/linux_learn/script/bin
username=$(whoami)
dir=$(pwd)
echo -e "your name is ${username}, and your directory is ${dir}"
exit 0
第二题
#!/bin/bash
#Program:
# chapter12 2nd exercise.
#History:
# 2023/02/06
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/linux_learn/script/bin
read -p "enter your birthday ex:0107 :" bday_now
bday_now_test=$(echo ${bday_now} | grep '[0-9]\{4\}')
if [ "$bday_now_test" == "" ];then #注意两边都有“”
echo "wrong date"
exit 1
fi
declare -i bday_afteryear=$(($(date +%Y)+ 1))
bday="${bday_afteryear}${bday_now}"
declare -i datenow=$(date +%s)
declare -i datebir=$(date --date="${bday}" +%s)
declare -i date=$(((${datebir}-${datenow})/60/60/24))
echo -e "ater ${date} days"