Shell脚本编程
- 一. SHELL入门
- 二. 判断与控制
- 三. 循环与控制
- 四. 变量的高级用法
- 五. 函数的高级用法
- 六. 文件查找
- 七. 文件处理三剑客之grep
- 八. Shell脚本操作数据库实战
- 九. 大型脚本工具开发实战
一. SHELL入门
1.1 变量
- 变量是由任何字母、数字、下划线组成的字符串,且不能以数字开头。
- 区分字母大小写
- 变量、等号、值中间不能出现任何空格
实例
注:$ var1+$ var2并不能实现相加,$ var1,$ var2默认作为字符串来处理
当一条命令或脚本执行时,后面可以跟多个参数,我们使用位置参数变量来表示这些参数。
位置参数变量 | 描述 |
---|---|
$n | n 为数字,$ 0 代表Shell本身的文件名,$ 1〜$ 9 代表第 1 ~ 9 个参数,10 以上的参数需要用大括号包含, 如 $ {10} |
$* | 命令行所有参数,把所有的参数看成一个整体 |
$@ | 命令行中所有参数,但每个参数区别对待 |
$# | 命令行中所有参数的个数 |
实例
$ @和$ *都表示命令行所有参数,但是$ *将命令行的所有参数看成一个整体,而$ @则区分各个参数
环境变量是在操作系统中一个具有特定名字的对象,它包含了一个或多个应用程序将使用到的信息。Linux是一个多用户的操作系统,每个用户登录系统时都会有一个专用的运行环境,通常情况下每个用户的默认的环境都是相同的。这个默认环境就是一组环境变量的定义。每个用户都可以通过修改环境变量的方式对自己的运行环境进行配置。
分类
-
对所有用户生效的环境变量 /etc/profile
-
对特定用户生效的环境变量 ~ /.bashrc或者~/.bash_profile
-
临时有效的环境变量 export
常用环境变量
环境变量 | 含义 |
---|---|
PATH | 命令搜索的路径 |
HOME | 用户家目录的路径 |
LOGNAME | 用户登录名 |
PWD | 当前所在路径 |
HISTFILE | 历史命令的保存文件 |
HISTSIZE | 历史命令保存的最大行数 |
HOSTNAME | 主机名 |
SHELL | 用户当前使用的SHELL |
PS1 | 一级命令提示符 |
TMOUT | 用户和系统交互过程的超时值 |
IFS | 系统输入分隔符 |
OFS | 系统输出分隔符 |
实例
1.2 管道
将一个命令的输出作为另一个命令的输入
实例
- 列出所有安装过的软件包
rpm -qa
rpm命令是RPM软件包的管理工具
- 1列出与python相关的软件包
rpm -qa | grep python
Linux grep 命令用于查找文件里符合条件的字符串。
-a :将 binary 文件以 text 文件的方式搜寻数据
-c :打印匹配次数
-f 两个文件相同行 如,grep -f file1 file2
-h 不显示匹配行所在文件名
-i :忽略大小写的不同,所以大小写视为相同
-l 只显示匹配到的文件名
-n :顺便输出行号
-o 只显示匹配的字符
-v :只显示不匹配的行。
--color=auto :可以将找到的关键词部分加上颜色的显示喔!
- 显示与python相关的软件包的行数
rpm -qa | grep python | wc -l
Linux wc命令用于计算字数
-c或--bytes或--chars 只显示Bytes数。
-l或--lines 只显示行数。
-w或--words 只显示字数。
--help 在线帮助。
--version 显示版本信息。
- 1
1.3 退出状态码
所有的shell命令都使用退出状态吗来告知shell它已执行完毕
退出状态码是一个0~255的整数值
Linux提供了一个$?来捕获退出状态码的值,所以,可以通过echo语句测试命令是否运行成功。
一般来讲,退出状态 0 表示正常执行,没有遭遇任何问题。其他非零的状态码均表示失败。
状态码 | 描述 |
---|---|
0 | 命令成功结束 |
1 | 一般性未知错误 |
2 | 不适合的shell 命令 |
126 | 找到了该命令但无法执行 |
127 | 没找到命令 |
128 | 无效的退出参数 |
128+x | 与linux信号x相关的严重错误 |
130 | 通过ctrl+C终止的命令 |
255 | 正常范围之外的退出状态码 |
实例
退出状态码是以上一条指令的返回结果为准
使用exit命令改变退出状态码
exit $exit_code
exit 48 或者 exit 125 或者exit 0
- 1
二. 判断与控制
2.1 if-then 语句
语法:
if command | condition
then
commands
fi
- 1
实例
#!/bin/bash
if pwd
then
echo "It works"
fi
- 1
2.2 if-then-else 语句
语法:
if command | condition
then
commands
else
commands
fi
- 1实例
#!/bin/bash
if pwd
then
echo "It works"
fi
2.3 嵌套if语句
语法:
if command | condition
then
commands
elif command | condition
then
commands
else
commands
fi
- 1
2.4 条件测试-数值比较
语法:
if condition
then
commands
fi
或者
if condition;then
commands
fi
- 1
数值比较
数值比较 | 含义 |
---|---|
n1 -eq n2 | n1和n2相等,则返回true;否则返回false |
n1 -ne n2 | n1和n2不相等,则返回true;否则返回false |
n1 -gt n2 | n1大于n2,则返回true;否则返回false |
n1 -ge n2 | n1大于等于n2,则返回true;否则返回false |
n1 -lt n2 | n1小于n2,则返回true;否则返回false |
n1 -le n2 | n1小于等于n2,则返回true;否则返回false |
实例
#!/bin/bash
if [ $1 -eq $2 ];then
echo "$1 = $2"
elif [ $1 -gt $2 ];then
echo "$1 > $2"
elif [ $1 -lt $2 ];then
echo "$1 < $2"
fi
- 1
2.5 条件测试-字符串比较
字符串比较
字符串比较 | 含义 |
---|---|
str1 = str2 | 相等比较 |
str1 != str2 | 不相等比较 |
str1 < str2 | str1小于str2为true |
str1 > str2 | str1大于str2为true |
-n str1 | str1长度不是0则为true |
-z str1 | str1长度是0则为true |
实例
#!/bin/bash
var1='hello'
var2='world'
if [ $var1 = $var2 ];then
echo "equal"
else
echo "not equal"
fi
- 1
#!/bin/bash
var1='hello'
var2='world'
if [ $var1 < $var2 ];then
echo "<"
else
echo ">"
fi
- 1
<被当作了重定向,需要进行转义
#!/bin/bash
var1='hello'var2='world'
if [ $var1 \< $var2 ];then
echo "<"
else
echo ">"
fi
- 1
#!/bin/bash
var1=''
var2='world'
if [ -n "$var1" ];then
echo "var1 is not null"
else
echo "var1 is null"
fi
- 1
2.6 条件测试-文件比较
文件比较
文件比较 | 含义 |
---|---|
-d file | file是否为目录 |
-f file | file是否为文件 |
-e file | file是否存在 |
-r file | file是否可读 |
-w file | file是否可写 |
-x file | file是否可执行 |
-s file | file存在且非空 |
file1 -nt file2 | file1比file2新为true |
file1 -ot file2 | file1比file2旧为true |
实例
#!/bin/bash
if [ -d /usr/local ];then
echo "yes"
else
echo "no"
fi
- 1
#!/bin/bash
if [ /usr/local/test1 -nt /usr/local/test2 ];then
echo "new"
else
echo "old"
fi
- 1
2.7 符合条件测试
语法:
语法1 “与”
if condition1 && condition2
then
commands
fi
语法2 “或”
if condition1 || condition2
then
commands
fi
- 1
实例
#!/bin/bash
var1=56
var2=34
var3=89
if [ $var1 -gt $var2 ] && [ $var2 -lt $var3 ];then
echo " $var1 > $var2 并且 $var2 < $var3"
fi
- 1
2.8 if-then中使用双括号
使用双括号进行算术运算
语法:
if ((expression))
then
commands
fi
- 1
注:
-
双括号结构中,变量名引用可以加$,也可以不加
-
运算符前后可以有空格,也可以没有
-
可以用于if,for,while等循环控制结构中
-
多个运算符使用逗号分隔
可用运算符
运算符 | 含义 |
---|---|
value++ | 后增 |
value– | 后减 |
++value | 先增 |
–value | 先减 |
! | 逻辑求反 |
== | 相等 |
> | 大于 |
< | 小于 |
>= | 大于等于 |
<= | 小于等于 |
&& | 逻辑与 |
实例
#!/bin/bash
a=10
((a+=10))
echo $a
- 1
2.9 if-then中使用双方括号
单方括号语法
if [ $n1 -gt $n2 ] && [ $n2 -lt $n3 ]
then
commands
fi
改为双方括号语法
if [ [$n1 -gt $n2 && $n2 -lt $n3 ]]
then
commands
fi
注:
双括号结构中,变量名引用必须加$
[[后面必须要空格,]]前面必须有空格
- 1
2.10 case命令
语法:
case $var in
pattern1)
commands
;;
pattern2)
commands;
;;
esac
- 1
实例:
#!/bin/bash
case $1 in
jack)
echo "hello,jack"
;;
mike)
echo "hello,mike"
;;
*)
echo "hello everyone"
;;
esac
- 1
三. 循环与控制
3.1 for循环
循环遍历一系列特定值,然后在结构体中针对每个特定值做处理
语法:
for var in list
do
commands
done
- 1
实例:
for循环读取列表值:
#!/bin/bash
for i in Beijing Shanghai Nanjing Guangzhou Zhengzhou
do
echo "Province is $i"
done
for i in {1..20}
do
echo "Number is $i"
done
- 1
for循环读取变量值:
#!/bin/bash
list="Zhangsan Lisi Mike Tom"
for i in $list
do
echo "Name is $i"
done
#!/bin/bash
IFS=$":" #分隔符,默认为空格或tab
list="Zhangsan:Lisi:Mike:Tom"
for i in $list
do
echo "Name is $i"
done
- 1
for循环从命令执行结果读取值
#!/bin/bash
FILE=$(ls /opt/)
for i in $FILE
do
echo "file is $i"
done
- 1
#!/bin/bash
for i in $(ls /opt/)
do
if [ -d /opt/$i ]
then
echo "$i is DIR"
elif [ -f /opt/$i ]
then
echo "$i is FILE"
fi
done
- 1
C语言风格的for循环
#!/bin/bash
for ((i=10;i<20;i++))
do
echo "Next Number is $i"
done
- 1
#!/bin/bash
sum=0
for (( i=1;i<101;i++))
do
(( sum+=$i ))
done
echo "sum is $sum"
- 1
3.2 while循环
语法:
while command
do
commands
done
实例:
#!/bin/bash
num=10
while [ $num -lt 20 ]
do
echo "number is $num"
((num++))
done
3.3 until命令
语法:
until command
do
commands
done
- 1
实例:
#!/bin/bash
num=10
until [ $num -eq 0 ]
do
echo "number is $num"
((num--))
done
3.4 break命令
实例:
#!/bin/bash
num=10
for ((i=1;i<=10;i++))
do
if ((i==5))
then
break
else
echo "number is $i"
fi
done
- 1
当有两层循环的时候,"break 1"跳出内循环; " break 2"跳出外循环
#!/bin/bash
num=10
for ((i=1;i<=10;i++))
do
for((j=1;j<=5;j++))
do
if ((j==3))
then
break 1
else
echo "$i $j"
fi
done
done
- 1
#!/bin/bash
num=10
for ((i=1;i<=10;i++))
do
for((j=1;j<=5;j++))
do
if ((j==3))
then
break 2
else
echo "$i $j"
fi
done
done
3.5 continue命令
实例:
#!/bin/bash
num=10
for ((i=1;i<=30;i++))
do
if ((i>15 && i<25))
then
continue
else
echo "Number is $i"
fi
done
- 1
3.6 处理循环的输出
实例
#!/bin/bash
num=10
for ((i=1;i<=100;i++))
do
echo "Number is $i"
done > result.txt
- 1
#!/bin/bash
num=10
for ((i=1;i<=100;i++))
do
echo "Number is $i"
done | grep "5"
- 1
四. 变量的高级用法
4.1 变量替换和测试
变量替换
语法 | 含义 |
---|---|
${变量名#匹配规则} | 从变量开头进行规则匹配,将符合最短的数据删除 |
${变量名##匹配规则} | 从变量开头进行规则匹配,将符合最长的数据删除 |
${变量名%匹配规则} | 从变量尾部进行规则匹配,将符合最短的数据删除 |
${变量名%%匹配规则} | 从变量尾部进行规则匹配,将符合最长的数据删除 |
${变量名/旧字符串/新字符串} | 变量内容符合旧字符串规则,则第一个旧字符串会被新字符串取代 |
${变量名//旧字符串/新字符串} | 变量内容符合旧字符串规则,则全部的旧字符串会被新字符串取代 |
实例
变量测试
实例
4.2 字符串处理
计算字符串长度
方法一:
${#string}
方法二:
expr length "$string" #string如果有空格,则必须加双引号
- 1
获取子串在字符串中的索引位置
语法
expr index $string $substring
- 1
$substring会被切割成字符,比如orl被切割成o,r,l,分别查找字符,哪个字符最先找到就会返回那个字符的位置,l最靠前,位置为3,返回3
计算子串长度
expr match $string substr
- 1
$string会从头开始匹配子串,不能从中间匹配
抽取子串
方法一:
${string:position} #从string中的position开始
方法二:
${string:position:length} #从position开始,匹配长度为length
方法三:
${string:-(position)} #从右边开始匹配
方法四:
${string:(position)} #从左边开始匹配
方法五:
expr substr $string $position $length #从position开始,匹配长度为length
- 1
练习
需求描述:
变量string=“Bigdata process framework is Hadoop,Hadoop is an open source project” 执行脚本后,打印输出string字符串变量,并给出用户以下选项:
- 打印string长度
- 删除字符串中所有的Hadoop
- 替换第一个Hadoop为Mapreduce
- 替换全部Hadoop为Mapreduce
用户输入数字1|2|3|4,可以执行对应项的功能;输入qlQ则退出交互模式
脚本:
read命令用于从标准输入中读取输入单行
-a:将分裂后的字段依次存储到指定的数组中,存储的起始位置从数组的index=0开始。
-d:指定读取行的结束符号。默认结束符号为换行符。
-n:限制读取N个字符就自动结束读取,如果没有读满N个字符就按下回车或遇到换行符,则也会结束读取。
-N:严格要求读满N个字符才自动结束读取,即使中途按下了回车或遇到了换行符也不结束。其中换行符或回车算一个字符。
-p:给出提示符。默认不支持"\n"换行,要换行需要特殊处理,见下文示例。例如,"-p 请输入密码:"
-r:禁止反斜线的转义功能。这意味着"\"会变成文本的一部分。
-s:静默模式。输入的内容不会回显在屏幕上。
-t:给出超时时间,在达到超时时间时,read退出并返回错误。也就是说不会读取任何内容,即使已经输入了一部分。
-u:从给定文件描述符(fd=N)中读取数据。
#!/usr/bin/env bash
string="Bigdata process framework is Hadoop,Hadoop is an open source project"
function tips_info
{
echo "******************************************"
echo "*** (1) 打印string长度"
echo "*** (2) 在整个字符串中删除Hadoop"
echo "*** (3) 替换第一个Hadoop为Mapreduce"
echo "*** (4) 替换全部Hadoop为Mapreduce"
echo "******************************************"
}
function print_len
{
if [ -z "$string" ];then
echo "Error,string is null"
exit 1
else
echo "${#string}"
fi
}
function del_hadoop
{
if [ -z "$string" ];then
echo "Error,string is null"
exit 1
else
echo "${string//Hadoop/}"
fi
}
function rep_hadoop_mapreduce_first
{
if [ -z "$string" ];then
echo "Error,string is null"
exit 1
else
echo "${string/Hadoop/Mapreduce}"
fi
}
function rep_hadoop_mapreduce_all
{
if [ -z "$string" ];then
echo "Error,string is null"
exit 1
else
echo "${string//Hadoop/Mapreduce}"
fi
}
while true
do
echo "【string=\"$string\"】"
tips_info
read -p "Pls input your choice(1|2|3|4|q|Q):" choice
case "$choice" in
1)
echo
echo "Length Of String is: `print_len`"
echo
continue
;;
2)
echo
echo "删除Hadoop后的字符串为:`del_hadoop`"
echo
;;
3)
echo
echo "替换第一个Hadoop的字符串为:`rep_hadoop_mapreduce_first`"
echo
;;
4)
echo
echo "替换第一个Hadoop的字符串为:`rep_hadoop_mapreduce_all`"
echo
;;
q|Q)
exit 0
;;
*)
echo "error,unlegal input,legal input only in { 1|2|3|4|q|Q }"
continue
;;
esac
done
- 1
- 40
4.3 命令替换
语法格式
方法一
`command`
方法二
$(command)
$(())两个括号用来进行,包括加减乘除数据运算,引用变量前面可以加$,也可以不加$
案例
获取系统的所有用户并输出
cut 命令从文件的每一行剪切字节、字符和字段并将这些字节、字符和字段写至标准输出。
如果不指定 File 参数,cut 命令将读取标准输入。必须指定 -b、-c 或 -f 标志之一。
参数:
-b :以字节为单位进行分割。这些字节位置将忽略多字节字符边界,除非也指定了 -n 标志。
-c :以字符为单位进行分割。
-d :自定义分隔符,默认为制表符。
-f :与-d一起使用,指定显示哪个区域。
-n :取消分割多字节字符。仅和 -b 标志一起使用。如果字符的最后一个字节落在由 -b 标志的 List 参数指示的范围之内,该字符将被写出;否则,该字符将被排除
#!/bin/bash
index=1
for user in `cat /etc/passwd | cut -d ":" -f 1`
do
echo "This is $index user: $user"
index=$(($index + 1))
done
根据系统时间计算今年或明年
Linux date命令可以用来显示或设定系统的日期与时间
时间方面:
% : 印出 %
%n : 下一行
%t : 跳格
%H : 小时(00..23)
%I : 小时(01..12)
%k : 小时(0..23)
%l : 小时(1..12)
%M : 分钟(00..59)
%p : 显示本地 AM 或 PM
%r : 直接显示时间 (12 小时制,格式为 hh:mm:ss [AP]M)
%s : 从 1970 年 1 月 1 日 00:00:00 UTC 到目前为止的秒数
%S : 秒(00..61)
%T : 直接显示时间 (24 小时制)
%X : 相当于 %H:%M:%S
%Z : 显示时区
日期方面:
%a : 星期几 (Sun..Sat)
%A : 星期几 (Sunday..Saturday)
%b : 月份 (Jan..Dec)
%B : 月份 (January..December)
%c : 直接显示日期与时间
%d : 日 (01..31)
%D : 直接显示日期 (mm/dd/yy)
%h : 同 %b
%j : 一年中的第几天 (001..366)
%m : 月份 (01..12)
%U : 一年中的第几周 (00..53) (以 Sunday 为一周的第一天的情形)
%w : 一周中的第几天 (0..6)
%W : 一年中的第几周 (00..53) (以 Monday 为一周的第一天的情形)
%x : 直接显示日期 (mm/dd/yy)
%y : 年份的最后两位数字 (00.99)
%Y : 完整年份 (0000..9999)
参数说明:
-d datestr : 显示 datestr 中所设定的时间 (非系统时间)
--help : 显示辅助讯息
-s datestr : 将系统时间设为 datestr 中所设定的时间
-u : 显示目前的格林威治时间
--version : 显示版本编号
根据系统时间获取今年还剩下多少星期,已经过了多少星期
判定nginx进程是否存在,若不存在则自动拉起该进程
#!/bin/bash
nginx_process_num=$(ps -ef | grep nginx | grep -v grep | wc -l)
if [ $nginx_process_num -eq 0 ];then
systemctl start nginx
fi
4.4 有类型变量
declare和typeset命令
- declare命令和typeset命令两者等价
- declare、typeset命令都是用来定义变量类型的
declare命令参数表
参数 | 含义 |
---|---|
-r | 将变量设为只读 |
-i | 将变量设为整数 |
-a | 将变量定义为数组 |
-f | 显示此脚本前定义过的所有函数及内容 |
-F | 仅显示此脚本前定义过的函数名 |
-x | 将变量声明为环境变量 |
输出数组内容:
echo $array[@]} 输出全部内容
echo ${array[1]} 输出下标索引为1的内容
获取数组长度:
echo ${#array} 数组内元素个数
echo ${#array[2]} 数组内下标索引为2的元素长度
给数组某个下标赋值:
array[0]="lily" 给数组下标索引为1的元素赋值为lily
array[20]="hanmeimei" 在数组尾部添加一个新元素
删除元素:
unset array[2] 清除元素
unset array 清空整个数组
分片访问:
${array[@]:1:4} 显示数组下标索引从1开始到3的3个元素,不显内容替换:
${array[@]/an/AN}将数组中所有元素内包含an的子串替换为AN
数组遍历:
for v in ${array[@]}
do
echo $v
done
- 1
4.5 bash数学运算
语法格式
方法一 expr $numl operator $num2
方法二 $(($num1 operator $num2))
expr操作符对照表
操作符 | 含义 |
---|---|
num1|num2 | num1不为空且非0,返回num1;否则返回num2 |
num1&num2 | num1不为空且非0,返回num1;否则返回0 |
num1<num2 | num1小于num2,返回1;否则返回0 |
num1<=num2 | num1小于等于num2,返回1;否则返回0 |
num1=num2 | num1等于num2,返回1;否则返回0 |
num1!=num2 | num1不等于num2,返回1;否则返回0 |
num1>num2 | num1大于num2,返回1;否则返回0 |
num1>=num2 | num1大于等于num2,返回1;否则返回0 |
num1+num2 | 求和 |
num1-num2 | 求差 |
num1*hum2 | 求积 |
num1/num2 | 求商 |
num1%num2 | 求余 |
在使用的时候需要进行转义
expr $numl \| $num2
expr $numl \& $num2
expr $numl \< $num2
expr $num1 \< $num2r
expr $numl \<=$num2
expr $num1 \>$num2
expr $numl \>=$num2
练习例子
提示用户输入一个正整数num,然后计算1+2+3+…+num的值;必须对num是否为正整数做判断,不符合应当再次允许输入
#!/bin/bash
#
while true
do
read -p "pls input a positive number: " num
expr $num + 1 &> /dev/null
if [ $? -eq 0 ];then
if [ `expr $num \> 0` -eq 1 ];then
for((i=1;i<=$num;i++))
do
sum=`expr $sum + $i`
done
echo "1+2+3+....+$num = $sum"
exit
fi
fi
echo "error,input enlegal"
continue
done
bc介绍
- bc是bash内建的运算器,支持浮点数运算
- 内建变量scale可以设置,默认为0
bc操作符对照表
操作符 | 含义 |
---|---|
num1+num2 | 求和 |
num1-num2 | 求差 |
num1*num2 | 求积 |
num1/num2 | 求商 |
num1%num2 | 求余 |
num1^num2 | 指数运算 |
五. 函数的高级用法
5.1 函数定义和使用
函数介绍
- Linux Shell中的函数和大多数编程语言中的函数一样
- 将相似的任务或代码封装到函数中,供其他地方调用
语法格式
第一种格式
name()
{
command1
command2
......
commandn
}
第二种格式
function name
{
command1
command2
......
commandn
}
如何调用函数
- 直接使用函数名调用,可以将其想象成Shell中的一条命令
- 函数内部可以直接使用参数$1、$2...$n
- 调用函数:function name $1 $2
实例
需求描述:写一个监控nginx的脚本;如果Nginx服务宕掉,则该脚本可以检测到并将进程启动,如果正常运行,则不做任何处理
#!/bin/bash
this_pid=$$
while true
do
ps -ef | grep nginx | grep -v grep | grep -v $this_pid &> /dev/null
if [ $? -eq 0 ];then
echo "Nginx is running well"
sleep 3
else
systemctl start nginx
echo "Nginx is down,Start it...."
fi
done
5.2 向函数传递参数
function name
{
echo "Hello $1"
echo "Hello $2"
}
函数调用:
name Lily Allen
实例
需求描述:
写一个脚本,该脚本可以实现计算器的功能,可以进行+ - * / 四种计算。
#!/bin/bash
function calcu
{
case $2 in
+)
echo "`expr $1 + $3`"
;;
-)
echo "`expr $1 - $3`"
;;
\\*)
echo "`expr $1 \* $3`"
;;
/)
echo "`expr $1 / $3`"
;;
esac
}
calcu $1 $2 $3
5.3 函数返回值
返回值的方式
方法一:
return
方法二:
echo
使用return返回值
- 使用return返回值,只能返回1-255的整数
- 函数使用return返回值,通常只是用来供其他地方调用获取状态,因此通常仅返回0或1;0表示成功,1表示失败
实例
#!/bin/bash
this_pid=$$
function is_nginx_running
{
ps -ef | grep nginx | grep -v grep | grep -v $this_pid &> /dev/null
if [ $? -eq 0 ];then
return
else
return 1
fi
}
is_nginx_running && echo "Nginx is running" || echo "Nginx is stoped"
使用echo返回值
- 使用echo可以返回任何字符串结果
- 通常用于返回数据,比如一个字符串值或者列表值
cut 命令从文件的每一行剪切字节、字符和字段并将这些字节、字符和字段写至标准输出。
-b :以字节为单位进行分割。这些字节位置将忽略多字节字符边界,除非也指定了 -n 标志。
-c :以字符为单位进行分割。
-d :自定义分隔符,默认为制表符。
-f :与-d一起使用,指定显示哪个区域。
-n :取消分割多字节字符。仅和 -b 标志一起使用。如果字符的最后一个字节落在由 -b 标志的 List 参数指示的范围之内,该字符将被写出;否则,该字符将被排除
#!/bin/bash
function get_users
{
users=`cat /etc/passwd | cut -d: -f1`
echo $users
}
user_list=`get_users`
index=1
for u in $user_list
do
echo "The $index user is : $u"
index=$(($index+1))
done
5.4 局部变量和全局变量
全局变量
- 不做特殊声明,Shell中变量都是全局变量
- Tips:大型脚本程序中函数中慎用全局变量
局部变量
- 定义变量时,使用local关键字
- 函数内和外若存在同名变量,则函数内部变量覆盖外部变量
#!/bin/bash
var1="Hello world"
function test
{
var2=87
}
echo $var1
echo $var2
test
echo $var1
echo $var2
#!/bin/bash
var1="Hello world"
function test
{
local var2=87
}
test
echo $var1
echo $var2
5.5 函数库
为什么要定义函数库
- 经常使用的重复代码封装成函数文件
- 一般不直接执行,而是由其他脚本调用
实例
定义一个函数库,该函数库实现以下几个函数
1、加法函数 add
2、减法函数 reduce
3、乘法函数 multiple
4、除法函数 divide
5、打印系统运行情况的函数sys_load,该函数可以显示内存情况
base_function
function add
{
echo "`expr $1 + $2`"
}
function reduce
{
echo "`expr $1 - $2`"
}
function multiple
{
echo "`expr $1 \* $2`"
}
function divide
{
echo "`expr $1 / $2`"
}
function sys_load
{
echo "Memory Info"
echo
free -m
echo
echo "Disk Usage"
echo
df -h
echo
}
test1.sh
#! /bin/bash
. /root/base_function
add 12 23
reduce 90 30
multiple 12 12
divide 12 2
sys_load
- 1
总结
- 库文件的后缀是任意的,但一般使用.lib
- 库文件通常没有可执行选项
- 库文件无需和脚本在同级目录,只需在脚本中引用时指定
- 第一行一般使用#!/bin/echo,输出警告信息,避免用户执行
六. 文件查找
6.1 find命令
语法格式
find [路径] [选项] [操作]
- 1
选项参数对照表
选项 | 含义 |
---|---|
-name | 根据文件名查找 |
-perm | 根据文件权限查找 |
-prune | 通常和-path一起使用,用于将特定目录排除在搜索条件之外 该选项可以排除某些查找目录 |
-user | 根据文件属主查找 |
-group | 根据文件属组查找 |
-mtime | 根据文件更改时间查找 |
-nogroup | 查找无有效属组的文件 |
-nouser | 查找无有效属主的文件 |
-newer file1 !file2 | 查找更改时间比file1新但比file2旧IDE文件 |
-type | 按文件类型查找 |
-size | 按文件大小查找 |
-mindepth n | 从n级子目录开始搜索 |
-maxdepth n | 最多搜索到n级子目录 |
-exec | 对搜索到的文件执行特定的操作,格式为-exec command {} \; |
注:
1、{} 和 \ 之间有空格
2、\ 和 ; 之间没有空格!
实例
-type
f 文件 find . -type f
d 目录 find . -type d
c 字符设备文件 find . -type c
b 块设备文件 find . -type b
l 链接文件 find . -type l
p 管道文件 find .-type p
目录下以conf结尾的文件
find /etc -name '*conf' #-name不区分大小写
查找当前目录下文件名为aa的文件,不区分大小写
find . -iname aa
查找文件属主为hdfs的所有文件
find . -user hdfs
查找文件属组为yarn的所有文件
find . -group yarn
查找/etc目录下小于10000字节的文件
find /etc -size -10000c
查找/etc目录下大于1M的文件
find /etc -size +1M
-mtime
-n n天以内修改的文件
+n n天以外修改的文件
n 正好n天修改的文件
查找/etc目录下5天之内修改且以conf结尾的文件
find /etc -mtime -5 -name1 '*.conf'
查找/etc目录下10天之前修改且属主为root的文件
find /etc -mtime +10 -user root
查找/etc目录下30分钟之前修改的文件
find /etc -mmin +30
查找/etc目录下30分钟之内修改的目录
find /etc -mmin -30 -type d
在/etc下的3级子目录开始搜索
find /etc -mindepth 3
在/etc下搜索符合条件的文件,但最多搜索到2级子目录
find /etc -maxdepth 2 -type f -name '*.conf'
查找没有属主的用户
find . -type f -nouser
查找没有属组的用户
find .-type f -nogroup
-perm例子:
find.-perm 664
查找当前目录下所有普通文件,但排除test目录
find . -path ./etc -prune -o -type f
查找当前目录下所有普通文件,但排除etc和opt目录
find . -path . /etc -prune -o -path ./opt -prune -o -type f
查找当前目录下所有普通文件,但排除etc和opt目录,但属主为hdfs
find . -path ./etc -prune -o -path ./opt -prune -o -type f -a -user hdfs
查找当前目录下所有普通文件,但排除etc和opt目录,但属主为hdfs,且文件大小必须大于500字节
find . -path ./etc -prune -o -path ./opt -prune -o -type f -a -user hdfs -a -size +500c
搜索/etc下的文件(非目录),文件名以conf结尾,且大于10k,然后将其删除
find . /etc/ -type f -name '*.conf' -size +10k -exec rm -f {} \;
将/var/1og/目录下以1og结尾的文件,且更改时间在7天以上的删除
find /var/log/ -name '*.log' -mtime +7 -exec rm -rf{} \;
搜索/etc下的文件(非目录),文件名以conf结尾,且大于10k,将其复制到/root/conf目录下
find . /etc/ -size +10k -type f -name '*.conf' -exec cp {} /root/conf/ \;
-ok 和exec功能一样,只是每次操作都会给用户提示
逻辑运算符:
-a 与
-o 或
-not | ! 非
查找当前目录下,属主不是hdfs的所有文件
find . -not -user hdfs | find . ! -user hdfs
查找当前目录下,属主属于hdfs,且大小大于300字节的文件
find . -type f -a -user hdfs -a -size +300c
查找当前目录下的属主为hdfs或者以xm1结尾的普通文件
find . -type f -a \( -user hdfs -o -name '*.xml' \)
6.2 find、locate、whereis和which总结及适用场景分析
locate命令
-
文件查找命令,所属软件包mlocate
-
不同于find命令是在整块磁盘中搜索,locate命令在数据库文件中查找
-
find是默认全部匹配,locate则是默认部分匹配
updatedb命令
-
用户更新/var/lib/mlocate/mlocate.db
-
所使用配置文件/etc/updatedb.conf
-
该命令在后台cron计划任务中定期执行
whereis命令
选项 | 含义 |
---|---|
-b | 只返回二进制文件 |
-m | 只返回帮助文档文件 |
-s | 只返回源代码文件 |
which命令
仅查找二进制程序文件
选项 | 含义 |
---|---|
-b | 只返回二进制文件 |
各命令使用场景推荐
命令 | 适用场景 | 优缺点 |
---|---|---|
find | 查找某一类文件,比如文件名部分一致 | 功能强大,速度慢 |
locate | 只能查找单个文件 | 功能单一,速度快 |
whereis | 查找程序的可执行文件、帮助文档等 | 不常用 |
which | 只查找程序的可执行文件 | 常用于查找程序的绝对路径 |
七. 文件处理三剑客之grep
7.1 grep命令
grep 命令用于查找文件里符合条件的字符串。
语法1:
grep [option] [ pattern] [file1, file2..]
语法2:
command | grep [option] [pattern]
选项 | 含义 |
---|---|
-v | 不显示匹配行信息 |
-i | 搜索时忽略大小写 |
-n | 显示行号 |
-r | 递归搜索 |
-E | 支持扩展正则表达式 |
-F | 不按正则表达式匹配,按照字符串字面意思匹配 |
-c | 只显示匹配行总数 |
-w | 匹配整词 |
-x | 匹配整行 |
-l | 只显示文件名,不显示内容 |
-s | 不显示错误信息 |
- grep默认不支持扩展正则表达式,只支持基础正则表达式
- 使用grep-E可以支持扩展正则表达式使用
- egrep可以支持扩展正则表达式,与grep-E等价
7.2 文件处理三剑客之sed
sed(Stream Editor),流编辑器。对标准输出或文件逐行进行处理
语法格式
语法一:
stdout |sed [option] "pattern command"
语法二:
sed [option] "pattern command" file
选项 | 含义 |
---|---|
-n | 只打印模式匹配行 |
-e | 直接在命令行进行sed编辑,默认选项 |
-f | 编辑动作保存在文件中,指定文件执行 |
-r | 支持扩展正则表达式 |
-i | 直接修改文件内容 |
edit.sed文件写入:
/python/p
- 1
pattern用法表
匹配模式 | 含义 |
---|---|
10command | 匹配到第10行 |
10,20command | 匹配从第10行开始,到第20行结束10, |
10,+5command | 匹配从第10行开始,到第16行结束 |
/pattern1/command | 匹配到pattern1的行 |
/pattern1/,/pattern2/command | 匹配到pattern1的行开始,到匹配到patern2的行结束 |
10,/pattern1/command | 匹配从第10行开始,到匹配到pettern1的行结束 |
/pattern1/,10command | 匹配到pattern1的行开始,到第10行匹配结束 |
实例
打印file文件的第17行
sed -n "17p" file
打印文件的10到20行
sed -n "10,20p" file
打印file文件中从第10行开始,往后面加5行
sed -n "10,+5p" file
打印file文件中以root开头的行
sed -n "/^root/p" file
打印file文件中第一个匹配到以ftp开头的行,到mail开头的行结束
sed -n "/^ftp/,/^mail/p" file
打印file文件中从第4行开始匹配,直到以hdfs开头的行结束
sed -n "4,/^hdfs/p" file
打印file文件中匹配root的行,直到第10行结束
sed -n "/root/,10p"file
编辑命令对照表
类别 | 编辑命令 | 含义 |
---|---|---|
查询 | p | 打印 |
= | 只显示行号 | |
增加 | a | 行后追加 |
i | 行前追加 | |
r | 外部文件读入,行后追加 | |
w | 匹配行写入外部文件 | |
删除 | d | 删除 |
修改 | s/old/new | 将行内第一个old替换为new |
s/old/new/g | 将行内全部的old替换为new | |
s/old/new/2g | 将行内从第2个old开始到剩下所有的old替换为new | |
s/old/new/ig | 将行内全部的old替换为new,忽略大小写 |
实例
先看一下例子
&和\1引用模式匹配到的整个串
两者区别在于只能表示匹配到的完整字符串,只能引用整个字符串;而\1可以使用()匹配到的字符
sed中引用变量时注意事项:
(1)、匹配模式中存在变量,则建议使用双引号
(2)、sed中需要引入自定义变量时,如果外面使用单引号,则自定义变量也必须使用单引号
#!/bin/bash
old_str=hadoop
new_str=HADOOP
sed -i "s/$old_str"/"$new_str/g" abc.txt
需求描述:
处理一个类似MySQL配置文件my.cnf的文本,示例如下;编写脚本实现以下功能:输出文件有几个段,并且针对每个段可以统计配置参数总个数
my.cnf
# this is read by the standalone daemon and embedded servers
[client]
port=3306
socket=/tmp/mysql.socket
#ThisSegmentForserver
[server]
innodb_buffer_pool_size=91750M
innodb_buffer_pool_instances=8
innodb_buffer_pool_load_at_startup=1
innodb_buffer_pool_dump_at_shutdown=1
innodb_data_file_path=ibdata1:1G:autoextend
innodb_flush_log_at_trx_commit=1
innodb_log_buffer_size=32M
innodb_log_file_size=2G
innodb_log_files_in_group=2
innodb_max_undo_log_size=4G
innodb_undo_directory=undolog
innodb_undo_tablespaces=95
#thisisonlyforthemysqldstandalonedaemon
[mysqld]
port=3306
socket=/tmp/mysql.sock
basedir=/usr/local/mysql
datadir=/data/mysql
pid-file=/data/mysql/mysql.pid
user=mysql
bind-address=0.0.0.0
sort_buffer_size=16M
join_buffer_size=16M
thread_cache_size=3000
interactive_timeout=600
wait_timeout=600
#ThisSegmentFormysqld_safe
[mysqld_safe]
log-error=/var/log/mariadb/mariadb.log
pid-file=/var/run/mariadb/mariadb.pid
max_connections=1000
open_files_limit=65535
thread_stack=512K
external-locking=FALSE
max_allowed_packet=32M
#thisisonlyforembeddedserver
[embedded]
gtid_mode=on
enforce_gtid_consistency=1
log_slave_updates
slave-rows-search-algorithms='INDEX_SCAN,HASH_SCAN'
binlog_format=row
binlog_checksum=1
relay_log_recovery=1
relay-log-purge=1
#usethisgroupforoptionsthatolderserversdon'tunderstand
[mysqld-5.5]
key_buffer_size=32M
read_buffer_size=8M
read_rnd_buffer_size=16M
bulk_insert_buffer_size=64M
myisam_sort_buffer_size=128M
myisam_max_sort_file_size=10G
myisam_repair_threads=1
lock_wait_timeout=3600
explicit_defaults_for_timestamp=1
innodb_file_per_table=1
预想输出结果:
1:client 2
2:server 12
3:mysqld 12
4:mysqld_safe 7
5:embedded 8
6:mysqld-5.5 10
脚本
#!/bin/bash
FILE_NAME=/root/Desktop/dir2/my.cnf
function get_all_segments
{
echo "`sed -n '/\[.*\]/p' $FILE_NAME |sed -e 's/\[//g' -e 's/\]//g'`"
}
function count_items_in_segment
{
echo "`sed -n '/\['$1'\]/,/\[.*\]/p' $FILE_NAME | grep -v ^# |grep -v ^$ |grep -v "\[.*\]" |wc -l `"
}
num=0
for seg in `get_all_segments`
do
num=`expr $num + 1`
items_count=`count_items_in_segment $seg`
echo "$num:$seg $items_count"
done
删除配置文件中的所有注释行和空行
sed -i '/[:blank:]*#/d;/^$/d' nginx.conf
在配置文件中所有不以#开头的行前面添加*符号,注意:以#开头的行不添加
sed -i 's/^[^#]/\*&/g' nginx.conf
修改用法总结:
1、1s/old/new/
2、5,10s/old/new/
3、10,+10s/old/new/
4、/pattern1/s/old/new/
5、/pattern1/,/pattern2/s/old/new/
6、/pattern1/,20s/old/new/
7、15,/pattern1/s/old/new/
- 1
修改/etc/passwd中第1行中第1个root为ROOT
sed -i '1s/root/ROOT/' passwd
修改/etc/passwd中第5行到第10行中所有的/sbin/nologin为/bin/bash
sed -i '5,10s/\/sbin\/nologin/\/bin\/bash/g' passwd
修改/etc/passwd中匹配到/sbin/nologin的行,将匹配到行中的login改为大写的LOGIN
sed -i '/\/sbin\/nologin/s/login/LOGIN/g' passwd
修改/etc/passwd中从匹配到以root开头的行,到匹配到行中包含mail的所有行。修改内为将这些所有匹配到的行中的bin改为HADOOP
sed -i '/^root/,/mail/s/bin/HADOOP/g' passwd
修改/etc/passwd中从匹配到以root开头的行,到第15行中的所有行,修改内容为将这些行中的nologin修改为SPARK
sed -i '/^root/,15s/nologin/SPARK/g' passwd
修改/etc/passwd中从第15行开始,到匹配到以yarn开头的所有航,修改内容为将这些行中的bin换位BIN
sed -i '15,/^yarn/s/bin/BIN/g' passwd
1、a 在匹配行后面追加
2、i 在匹配行前面追加
3、r 将文件内容追加到匹配行后面
4、w 将匹配行写入指定文件
实例
1、a append
(1)、passwd文件第10行后面追加"Add Line Behind"
sed -i '10a Add Line Begind' passwd
(2)、passwd文件第10行到第20行,每一行后面都追加"Test Line Behind"
sed -i '10,20a Test Line Behind' passwd
(3)、passwd文件匹配到/bin/bash的行后面追加"Insert Line For /bin/bash Behind"
sed -i '/\/bin\/bash/a Insert Line For /bin/bash Behind' passwd
2、i
(1)、passwd文件匹配到以yarn开头的行,在匹配行前面追加"Add Line Before"
sed -i '/^yarn/i Add Line Before' passwd
(2)、passwd文件每一行前面都追加"Insert Line Before Every Line"
sed -i 'i Insert Line Before Every Line' passwd
3、r
(1)、将/etc/fstab文件的内容追加到passwd文件的第20行后面
sed -i '20r /etc/fstab' passwd
(2)、将/etc/inittab文件内容追加到passwd文件匹配/bin/bash行的后面
sed -i '/\/bin\/bash/r /etc/inittab' passwd
(3)、将/etc/vconsole.conf文件内容追加到passwd文件中特定行后面,匹配以ftp开头的行,到第18行的所有行
sed -i '//,18r /etc/vconsole.conf' passwd
4、w
(1)、将passwd文件匹配到/bin/bash的行追加到/tmp/sed.txt文件中
sed -i '/\/bin\/bash/w /tmp/sed.txt' passwd
(2)、将passwd文件从第10行开始,到匹配到hdfs开头的所有行内容追加到/tmp/sed-1.txt
sed -i '10,/^hdfs/w /tmp/sed-1.txt' passwd
7.3 文本处理三剑客之awk
awk是一个文本处理工具,通常用于处理数据并生成结果报告
awk 'BEGIN{} pattern{commands}END{}' file_name
standard output | awk 'BEGIN{}pattern{commands}END{}'
- 1
- 2
语法格式说明
语法格式 | 解释 |
---|---|
BEGIN{} | 正式处理数据之前执行 |
pattern | 匹配模式 |
{commands} | 处理命令,可能多行 |
END{} | 处理完所有匹配数据后执行 |
内置变量 | 含义 |
---|---|
$0 | 打印行所有信息 |
$1~$n | 打印行的第1到n个字段的信息 |
NF | Number Field 处理行的字段个数 |
NR | Number Row 处理行的行号,从1开始计数 |
FNR | File Number Row 多文件处理时,每个文件单独记录行号,都是从0康凯斯 |
FS | Field Separator 字段分割符,不指定时默认以空格或tab键分割 |
RS | Row Separator 行分隔符,不指定时以回车分割\n |
OFS | Output Filed Separator 输出字段分隔符。 |
ORS | Output Row Separator 输出行分隔符 |
FILENAME | 处理文件的文件名 |
ARGC | 命令行参数个数 |
ARGV | 命令行参数数组 |
格式符
格式符 | 含义 |
---|---|
%s | 打印字符串 |
%d | 打印10进制数 |
%f | 打印浮点数 |
%x | 打印16进制数 |
%o | 打印8进制数 |
%e | 打印数字的科学计数法格式 |
%c | 打印单个字符的ASCII码 |
修饰符 | 含义 |
---|---|
- | 左对齐 |
+ | 右对齐 |
# | 显示8进制在前面加o,显示16进制在前面加0x |
实例
1、以字符串格式打印/etc/passwd中的第7个字段,以":"作为分隔符
awk 'BEGIN{FS=":"} {printf "%s\n",$7}' /etc/passwd
2、以10进制格式打印/etc/passwd中的第3个字段,以":"作为分隔符
awk 'BEGIN{FS=":"} {printf "%d\n",$3}' /etc/passwd
3、以浮点数格式打印/etc/passwd中的第3个字段,以":"作为分隔符
awk 'BEGIN{FS=":"} {printf "%0.3f\n",$3}' /etc/passwd
4、以16进制数格式打印/etc/passwd中的第3个字段,以":"作为分隔符
awk 'BEGIN{FS=":"} {printf "%#x\n",$3}' /etc/passwd
5、以8进制数格式打印/etc/passwd中的第3个字段,以":"作为分隔符
awk 'BEGIN{FS=":"} {printf "%#o\n",$3}' /etc/passwd
6、以科学计数法格式打印/etc/passwd中的第3个字段,以":"作为分隔符
awk 'BEGIN{FS=":"} {printf "%e\n",$3}' /etc/passwd
第一种
RegExp 按正则表达式匹配
第二种
关系运算匹配 按关系运算匹配
RegExp
匹配/etc/passwd文件行中含有root字符串的所有行
awk 'BEGIN{FS=":"}/root/{print $0}' /etc/passwd
- 1
匹配/etc/passwd文件行中以yarn开头的所有行
awk 'BEGIN{FS=":"}/^yarn/{print $0}' /etc/passwd
- 1
运算符匹配
< 小于
> 大于
<= 小于等于
>= 大于等于
== 等于
!= 不等于
~ 匹配正则表达式
!~ 不匹配正则表达式
实例
以:为分隔符,匹配/etc/passwd文件中第3个字段小于50的所有行信息
awk 'BEGIN{FS=":"}$3<50{print $0}' /etc/passwd
以:为分隔符,匹配/etc/passwd文件中第3个字段大于50的所有行信息
awk 'BEGIN{FS=":"}$3>50{print $0}' /etc/passwd
以:为分隔符,匹配/etc/passwd文件中第7个字段为/bin/bash的所有行信息
awk 'BEGIN{FS=":"}$7=="/bin/bash"{print $0}' /etc/passwd
以:为分隔符,匹配/etc/passwd文件中第7个字段不为/bin/bash的所有行信息
awk 'BEGIN{FS=":"}$7!="/bin/bash"{print $0}' /etc/passwd
以:为分隔符,匹配/etc/passwd中第3个字段包含3个以上数字的所有行信息
awk 'BEGIN{FS=":"}$3~/[0-9]{3,}/{print $0}' /etc/passwd
布尔运算符匹配:
|| 或
&& 与
! 非
实例
以:为分隔符,匹配/etc/passwd文件中包含hdfs或yarn的所有行信息
awk 'BEGIN{FS=":"}$1=="hdfs" || $1=="yarn" {print $0}' /etc/passwd
以:为分隔符,匹配/etc/passwd文件中第3个字段小于50并且第4个字段大于50的所有行信息
awk 'BEGIN{FS=":"}$3<50 && $4>50 {print $0}' /etc/passwd
运算符 | 含义 |
---|---|
+ | 加 |
/ | 除 |
% | 模 |
^或** | 乘方 |
++x | 在返回x变量之前,×变量加1 |
X++ | 在返回x变量之后,×变量加1 |
实例
使用awk计算/etc/services中的空白行数量
awk '/^$/{sum++}END{print sum}' /etc/services
- 1
计算学生课程分数平均值,学生课程文件内容如下:
Allen 80 90 96 98
Mike 93 98 92 91
Zhang 78 76 87 92
Jerry 86 89 68 92
Han 85 95 75 90
Li 78 88 98 100
awk '{total=$2+$3+$4+$4;AVG=total/4;printf "%-8s%5d%5d%5d%5d%0.2f\n",$1,$2,$3,$4,$5,AVG}' student.txt
- 1
条件语句:
if(条件表达式1)
动作
else if(条件表达式2)
动作
else
动作
以:为分隔符,只打印/etc/passwd中第3个字段的数值在50-100范围内的行信息
awk 'BEGIN{FS=":"}{if($3<50){ printf "%-20s%-20s%-5d\n","小于50的UID",$1,$3} else if($3>100) {printf "%-20s%-20s%-5d\n","大 于100的UID",$1,$3} else{ printf "%-20s%-20s%-5d\n","大于50 小于100的UID",$1,$3}}' /etc/passwd
- 1
- 2
循环语句:
while循环:
while(条件表达式)
动作
do while循环:
do
动作
while(条件表达式)
for循环:
for(初始化计数器;计数器测试;计数器变更)
动作
实例:
计算1+2+3+4+…+100的和,请使用while、do while、for三种循环方式实现
while
BEGIN{
while(i<=100) #不需要事先声明
{
sum+=i
i++
}
print sum
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
for
BEGIN{
for(i=0;i<=100;i++) #不需要事先声明
{
sum+=i
}
print sum
}
do while
BEGIN{
do
{
sum+=i
i++
}while(i<=100)
print sum
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
函数名 | 解释 |
---|---|
length(str) | 计算长度 |
index(str1,str2) | 返回在str1中查询到的str2的位置 |
tolower(str) | 小写转换 |
toupper(str) | 大写转换 |
split(str,arr,fs) | 分隔字符串,并保存到数组中 |
match(str,RE) | 返回正则表达式匹配到的子串的位置 |
substr(str,m,n) | 截取子串,从m个字符开始,截取n位。n若不指定,则默认截取到字符串尾 |
sub(RE,RepStr,str) | 替换查找到的第一个子串 |
gsub(RE,RepStr,str) | 替换查找到的所有子串 |
以:为分隔符,返回/etc/passwd中每行中每个字段的长度
root: x:0:0:root:/root:/bin/bash
4:1:1:1:4:5:9
BEGIN{
FS=":"
}
{
i=0
while(i<=NF)
{
if(i==NF)
printf "%d",length($i)
else
printf "%d:",length($i)
i++
}
print ""
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
搜索字符串"I have a dream"中出现"ea"子串的位置
awk 'BEGIN{str=“I hava a dream”;location=index(str,“ea”);print location}
awk ‘BEGIN{str=“I hava a dream”;location=match(str,“ea”);print location}’
将字符串"Hadoop is a bigdata Framawork"全部转换为小写
awk ‘BEGIN{str=“Hadoop is a bigdata Framework”;print tolower(str)}’
将字符串"Hadoop is a bigdata Framawork"全部转换为大写
awk ‘BEGIN{str=“Hadoop is a bigdata Framework”;print toupper(str)}’
将字符串"Hadoop Kafka Spark Storm HDFS YARN Zookeeper",按照空格为分隔符,分隔每部分保存到数组array中
awk ‘BEGIN{str=“Hadoop Kafka Spark Storm HDFS YARN Zookeeper”;split(str,arr," ");for(a in arr) print arr[a]}’
搜索字符串"Tranction 2345 Start:Select * from master"第一个数字出现的位置
awk ‘BEGIN{str=“Tranction 2345 Start:Select * from master”;location=match(str,/[0-9]/);print location}’
截取字符串"transaction start"的子串,截取条件从第4个字符开始,截取5位
awk ‘BEGIN{str=“transaction start”;print substr(str,4,5)}’
替换字符串"Tranction 243 Start,Event ID:9002"中第一个匹配到的数字串为$符号
awk ‘BEGIN{str=“Tranction 243 Start,Event ID:9002”;count=sub(/[0-9]+/,"$",str);print count,str}’
awk ‘BEGIN{str=“Tranction 243 Start,Event ID:9002”;count=gsub(/[0-9]+/,"$",str);print count,str}’
选项 | 解释 |
---|---|
-v | 参数传递 |
-f | 指定脚本文件 |
-F | 指定分隔符 |
-V | 查看awk的版本号 |
shell中数组的用法:
打印元素:
echo ${array[2]}
打印元素个数:
echo ${#array[@]}
打印元素长度:
echo ${#array[3]}
给元素赋值:
array[3]="Li"
删除元素:
unset array[2];unset array
分片访问:
echo ${array[@]:1:3}
元素内容替换:
${array[@]/e/E}只替换第一个e;
$tarray[@]//e/E}替换所有的e
数组的遍历:
for a in array
do
echo $a
done
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
awk中数组的用法
在awk中,使用数组时,不仅可以使用1.2…n作为数组下标,也可以使用字符串作为数组下标
当使用1.2.3…n时,直接使用array[2]访问元素;需要遍历数组时,使用以下形式:
str="Allen Jerry Mike Tracy Jordan Kobe Garnet"
split(str,array," ")
for(i=1;i<length(array);i++)
print array[i]
- 1
- 2
- 3
- 4
当使用字符串作为数组下标时,需要使用array[str]形式访问元素;遍历数组时,使用以下形式:
array["var1"]="Jin"
array["var2"]="Hao"
array["var3"]="Fang"
for(a in array)
print array[a]
- 1
- 2
- 3
- 4
- 5
- 统计主机上所有的TCP连接状态数,按照每个TCP状态分类
netstat -an | grep tcp | awk '{array[$6]++} END{for(a in array) print a,array[a]}'
- 1
2. 计算横向数据总和,纵向数据总和
allen 80 90 87 91
mike 78 86 93 96
Kobe 66 92 82 78
Jerry 98 74 66 54
Wang 87 21 100 43
BEGIN{
printf "%-10s%-10s%-10s%-10s%-10s%-10s\n","Name","Yuwen","Math","English","Physical","Total"
}
{
total=$2+$3+$4+$5
yuwen_sum+=$2
math_sum+=$3
english_sum+=$4
physical_sum+=$5
printf "%-10s%-10d%-10d%-10d%-10d%-10d\n",$1,$2,$3,$4,$5,total
}
END{
printf "%-10s%-10d%-10d%-10d%-10d\n","total",yuwen_sum,math_sum,english_sum,physical_sum
}