SHELL 基础
一,特殊的shell变量
变量含义
$0 脚本名字
$1 位置参数 #1
$2 - $9 位置参数 #2 - #9
${10} 位置参数 #10
$# 位置参数的个数
"$*" 所有的位置参数(作为单个字符串) *
"$@" 所有的位置参数(每个都作为独立的字符串)
${#*} 传递到脚本中的命令行参数的个数
${#@} 传递到脚本中的命令行参数的个数
$? 返回值(上个命令是否成功执行)
$$ 脚本的进程ID(PID)
$- 传递到脚本中的标志(使用set)
$_ 之前命令的最后一个参数
$! 运行在后台的最后一个作业的进程ID(PID)
例:
#!/bin/bash
if [ "$#" -eq "2" ];then
echo "My first parameter is $1"
echo "My second parameter is $2"
else
echo "Usage: `basename $0` first second"
echo "You provided $# parameters,but 2 are required."
fi
二,字符串测试比较
(一定得加双引号"")
算术比较 字符串比较
-eq 等于 = 等于
== 等于
-ne 不等于 != 不等于
-lt 小于 \< 小于 (ASCII) *
-le 小于等于
-gt大于 \> 大于 (ASCII) *
-ge 大于等于
-z 字符串为空
-n 字符串不为空
三,文件类型的测试操作
操作测试条件
-e 文件是否存在
-s 文件大小为0 则真
-f 是一个标准文件
-d 是一个目录
-r 文件具有读权限
-h 文件是一个符号链接
-w 文件具有写权限
-L 文件是一个符号链接
-x 文件具有执行权限
-b 文件是一个块设备
-c 文件是一个字符设备
-g 设置了sgid标记
-p 文件是一个管道
-u 设置了suid标记
-S 文件是一个socket
-k 设置了"粘贴位"
-t 文件与一个终端相关联
-N 从这个文件最后一次被读取之后, 它被修改过
-O 这个文件的宿主是你
-G 文件的组id与你所属的组相同
! "非" (反转上边的测试结果)
F1 -nt F2 文件F1比文件F2新 *
F1 -ot F2 文件F1比文件F2旧 *
F1 -ef F2文件F1和文件F2都是同一个文件的硬链接 *
三,参数替换和扩展
表达式含义
${var} 变量var的值, 与$var相同
${var-DEFAULT} 如果var没有被声明, 那么就以$DEFAULT作为其值 *
${var:-DEFAULT} 如果var没有被声明, 或者其值为空, 那么就以$DEFAULT作为其值 *
${var=DEFAULT} 如果var没有被声明, 那么就以$DEFAULT作为其值 *
${var:=DEFAULT} 如果var没有被声明, 或者其值为空, 那么就以$DEFAULT作为其值 *
${var+OTHER} 如果var声明了, 那么其值就是$OTHER, 否则就为null字符串
${var:+OTHER} 如果var被设置了, 那么其值就是$OTHER, 否则就为null字符串
${var?ERR_MSG} 如果var没被声明, 那么就打印$ERR_MSG *
${var:?ERR_MSG} 如果var没被设置, 那么就打印$ERR_MSG *
${!varprefix*} 匹配之前所有以varprefix开头进行声明的变量
${!varprefix@} 匹配之前所有以varprefix开头进行声明的变量
${#string} $string的长度
${string:position} 在$string中, 从位置$position开始提取子串
${string:position:length} 在$string中, 从位置$position开始提取长度为$length的子串
${string#substring} 从变量$string的开头, 删除最短匹配$substring的子串
${string##substring} 从变量$string的开头, 删除最长匹配$substring的子串
${string%substring} 从变量$string的结尾, 删除最短匹配$substring的子串
${string%%substring} 从变量$string的结尾, 删除最长匹配$substring的子串
${string/substring/replacement} 使用$replacement, 来代替第一个匹配的$substring
${string//substring/replacement} 使用$replacement, 代替所有匹配的$substring
${string/#substring/replacement} 如果$string的前缀匹配$substring, 那么就用$replacement来代替匹配到的$substring
${string/%substring/replacement} 如果$string的后缀匹配$substring, 那么就用$replacement来代替匹配到的$substring
expr match "$string" '$substring' 匹配$string开头的$substring*的长度
expr "$string" : '$substring' 匹配$string开头的$substring*的长度
expr index "$string" $substring 在$string中匹配到的$substring的第一个字符出现的位置
expr substr $string $position $length在$string中从位置$position开始提取长度为$length的子串
expr match "$string" '\($substring\)' 从$string的开头位置提取$substring*
expr "$string" :'\($substring\)' 从$string的开头位置提取$substring*
expr match "$string"'.*\($substring\)' 从$string的结尾提取$substring*
expr "$string" :'.*\($substring\)' 从$string的结尾提取$substring*
四,一些结构的汇总表达式解释
中括号
if [ CONDITION ] 测试结构 (注意两边有空)
if [[ CONDITION ]] 扩展的测试结构
Array[1]=element1 数组初始化
[a-z] 正则表达式的字符范围
大括号
${variable} 参数替换
${!variable} 间接变量引用
{ command1; command2; . . . commandN; } 代码块
{string1,string2,string3,...} 大括号扩展
圆括号
( command1; command2 ) 子shell中执行的命令组
Array=(element1 element2 element3) 数组初始化
result=$(COMMAND) 在子shell中执行命令, 并将结果赋值给变量
>(COMMAND) 进程替换
<(COMMAND) 进程替换
双圆括号
(( var = 78 )) 整型运算
var=$(( 20 + 5 )) 整型运算, 并将结果赋值给变量
引号
"$variable" "弱"引用
'string' "强"引用
后置引用
result=`COMMAND` 在子shell中运行命令, 并将结果赋值给变量
五,正则表达式与通配符
正则表达式
---------用来在文件中的字符串的,
---------是包含匹配(字符串的一部分能匹配字符串)
例:搜索aa只要包含aa字符串的文本都能搜索出来)grep awk sed
通配符?* []
-----------用来搜索文件名的,完全匹配(必须得完一样)
-----------之所以通配符是用来匹配文件名的,是为ls这些命令只认识通配符
----------因为是完全匹配,假如说有aa aabb两个文件,ls aa命令时,则只能找到aa一个文件
---------*号也是匹配0次或多次,任意字符
元字符(即特殊字符,通配符)
返斜线 \ 为脱义符
元字符;
. 匹配换行符外的任意字符
[a-z0-9] 匹配集合中的任意单字符
[^a-z0-9] 匹配不在集合中的任意单字符
\d 匹配单个数字 等效于[0-9]
\D 匹配非数字,等效于[^0-9] 即
\w 匹配数字型的字符 等效于[0-9]
\W 匹配非数字型的,字符 相当于[^0-9]
\s 匹配空格
\S 匹配非空格
\n 匹配换行符
\r 匹配回车符
\t 匹配制表符
\0 匹配空值字符
锚定字符;
\b 匹配字边界(不在[]中)
\B 匹配非字边界
^ 匹配行首
$ 匹配行尾 (和行首一样,行首行尾不仅包含可见字符,也可能是不可见的)
\A 匹配字符串开头
\Z 匹配字符串或行未尾
\z 只匹配字符串未尾
\G 匹配前一次m//g
重复次数字符
x? 匹配0个或1个x
x* 匹配0个或多个
x+ 匹配1个或多个
(xyz)+ 匹配1个或多个
x{m,n} 匹配m个到n个(m要比n小)
替换字符;
|
例;(was|were|will)
匹配was或were或will之一
思考;三者之间匹配2个呢???
其它字符;
\12 匹配八进制数
\x811 匹配十六进制数
\cX 匹配控制字符
\e 匹配ASCII
\x{NUMBER} 匹配十六进制形式给出的Unicode
常用正则表达式
* ------前一个字符匹配0次或多次(只能代表前一个字符)
. -----------代表除了换行符之外的任意一个字符
^ ---------匹配行首(例:^hello 匹配以hello为行首的字符)
$ --------匹配行尾(例 hello$)
[] --------匹配中括号中的多个字符中的一个(选一个字符)
[^ ] ----匹配除中括号中字符以外的任意一个字符
\ ---------------脱义符,取消后面特殊符号的意义
\{n\} -----------表示前面的字符恰号出现n次,
(例子:[0-9]\{4\}表示[0-9]出现4次A\{n\}表示出现4次A)
\{n,\} -------表示前面的字符出现不小于n次
(例:[0-9]\{4,\}表示四位及四位以上的数)
\{n,m\} --------表示前面的为字符,最少出现n次,最多出现m次
(例子:[a-z]\{6,8\}匹配6到8位的小写字母)
六,grep命令
grep参数
语法:
grep -[acinv] '搜索内容串' filename
-a 将二进制文档以文本方式处理
-c 计算找到的符合行的次数
-i 忽略大小写
-n 顺便输出行号
-v 反向选择,即显示不包含匹配文本的所有行
-h 查询多文件时不显示文件名。
-l 查询多文件时只输出包含匹配字符的文件名。
-s 不显示不存在或无匹配文本的错误信息。
- E参数,这一扩展允许使用扩展模式匹配。
grep举例
关于匹配的实例:
grep -c "48" test.txt 统计所有以“48”字符开头的行有多少
grep -i "May" test.txt 不区分大小写查找“May”所有的行)
grep -n "48" test.txt 显示行号;显示匹配字符“48”的行及行号,相同于 nl test.txt |grep 48)
grep -v "48" test.txt 显示输出没有字符“48”所有的行)
grep "471" test.txt 显示输出字符“471”所在的行)
grep "48;" test.txt 显示输出以字符“48”开头,并在字符“48”后是一个tab键所在的行
grep "48[34]" test.txt 显示输出以字符“48”开头,第三个字符是“3”或是“4”的所有的行)
grep "^[^48]" test.txt 显示输出行首不是字符“48”的行)
grep "[Mm]ay" test.txt 设置大小写查找:显示输出第一个字符以“M”或“m”开头,以字符“ay”结束的行)
grep "K…D" test.txt 显示输出第一个字符是“K”,第二、三、四是任意字符,第五个字符是“D”所在的行)
grep "[A-Z][9]D" test.txt 显示输出第一个字符的范围是“A-D”,第二个字符是“9”,第三个字符的是“D”的所有的行
grep "[35]..1998" test.txt 显示第一个字符是3或5,第二三个字符是任意,以1998结尾的所有行
grep "4/{2,/}" test.txt 模式出现几率查找:显示输出字符“4”至少重复出现两次的所有行
grep "9/{3,/}" test.txt 模式出现几率查找:显示输出字符“9”至少重复出现三次的所有行
grep "9/{2,3/}" test.txt 模式出现几率查找:显示输出字符“9”重复出现的次数在一定范围内,重复出现2次或3次所有行
grep -n "^$" test.txt 显示输出空行的行号
ls -l |grep "^d" 如果要查询目录列表中的目录 同:ls -d *
ls -l |grep "^d[d]" 在一个目录中查询不包含目录的所有文件
ls -l |grpe "^d…..x..x" 查询其他用户和用户组成员有可执行权限的目录集合
七、printf和 echo命令
区别
echo只是回显没有变量替换功能;
printf是有的
举例:
假如我们定义好变量a='hello world'
则 echo "%s" $a 显示的结果就是%s
而 printf "%s\n" $a 显示的结果就是hello world
linux中只有printf命令
而awk中,有print和printf命令
语法
printf '输出类型输出格式' 输出内容
输出类型:
%ns:输出字符串。n是数字指代输出几个字符。
%ni:输出整数。n是数字指代输出几个数字。
%m.n:输出浮点数。m和n是数字,指代输出的整数位数和小数
如%8.2代表共输出8位数,其中2位是小数,6位是整数。
举例
[root@localhost ~]# printf %s 1 2 3 4 5 6
123456[root@localhost ~]# printf %s %s %s 1 2 3 4 5 6
%s%s123456[root@localhost ~]# printf '%s %s %s' 1 2 3 4 5 6
1 2 34 5 6[root@localhost ~]# printf '%s\t%s\t%s\n' 1 2 3 4 5 6
1 2 3
4 5 6
[root@localhost ~]# printf '%s' $(cat student.txt)
1furongF852fengjF603cangF70[root@localhost ~]#
[root@localhost ~]# printf '%s\t%s\t%s\t%s\n' $(cat student.txt)
1 furong F 85
2 fengj F 60
3 cang F 70
说明:以上printf打印文件的方式,其实用awk来实现更好控制
八、算术运算
1,(())双括号形式
z=$(($a+2)) --正确
z=$((a+3)) --正确
echo $((b+3)) --正确
说明:
使用双括号的形式最后,可以进行多种运算
而其它的如expr 和 set 则支持的运算不全
2,bc命令
它是linux下的计算器,即可以命令行中使用,也可以在脚本文件中使用
说明;
它最大的特点就是支持小数运算
echo 4.5+5|bc --结果9.5
seq -s "+" 10 |bc --结果是55 它计算的是1+2+3+....10
补充 : echo "scale=2; 2.3/32"|bc
scale=2表示有保留小数点后两位
obase=2表示是以二进制形式显示出来
obase=16表示以十六进制形式显示出来
解释:
即在表达式后面使用|bc ,即将表达式,交给bc来处理
3,$[ 表达式] 和$((表达式))效果差不多
九、shell变量从终端输入
补充;
---一种方法,我们使用命令行传参来进行赋值的 $1 $2 $3 ...
---另一方法 直接赋值
---还可以使用read[参数][变量名]
例;read -p a1 a2 回车
输入12 34 回车
则即把 12 34 分别赋值给a1和a2
例 ;
read -t 3 -p "请输入" a1 a2
显示请输入 等3秒 如果3秒内没有动作 则自动退出执行命令
- p 表示后面是给用户看的
-t 后面的数字表示是待等的时间
2,echo -n "请输入" --这是给用户看的 -n表示不换行(请输入后,不换行)
read a b ---这是要输入变量
3,直接使用
read a b 则会等待用户输入
注意;
如输入 12.3 45 56
则;a值是12.3 b值是 45 56
--说明;以下是判断输入的变量是否为数字,如果不为数字则重新输入
read -t 10 -p "请输入:" a b
expr $a + 0 > &/dev/null
[ $? -ne 0 ] && read -t 10 -p "请重输入:" a b
expr $b + 0 > &/dev/null
[ $? -ne 0 ] && read -t 10 -p "请重输入:" a b
十、条件测试
文件测试
语法说明;
格式1:test< >
格式2:[ ] --推荐使用此方法,所以后面不写[[]]格式的用法
格式3:[[ ]]
(())只能适用于整数测试
例;
一般操作文件时,都要先判断文件是否存在
test -f file && echo 1 ||echo 0
----即判断文件存不存在,则不会echo 1 而会运行 echo 0
test ! -f file && echo 1||echo 0
---和上面相反
[ -f file ] && echo 1 || echo 0
[ -f file -a -d foler ] && echo 1 || echo 0
[ -f file -r -d foler ] && echo 1 || echo 0
----即判断文件存不存在,则不会echo 1 而会运行 echo 0
----注意中括号两边有空格
---- - o表示或者 ,-a 表示and
说明;
-f 文件是否存在
-d 目录是否存在
-e 文件或目录是否存在
-w/-r/-x 权限判断
-s 文件存在,并且文件大小大于0则返回真
字符串测试
是否相同
是否长度为零
是否为NULL (bash区分null和零长度)
[ -z "str" ] 若长度为0 zero 则为真
[ -n "str" ] 若长度非0 则为真
[ "str1"="str2" ]
[ "str1"=="str2" ] 相等 则为真
[ "str1"!="str2" ] 不等 则为真
-----以上字符串操作,必须要用""括起来
特别说明;
如果是(())
测试数字时,则使用 == < > <= >=
-----(说明在使用圆括号(())时,必须使用双等号==,否则会被认为是赋值 )
-----它只能测试数字
如果是[] --推荐使用此方法,
测试数字时,则使用 -eq -ne -gt -ge -lt -le (等于,不等于,大于,小于,小于等于)
测试字符中时,由使用 == = != -z -n
测试文件时,则使用-f -d -e -x 多文件时使用 -a -o
如果混着用,即[]使用< > = >= 。。则必须\<进行转义
十一、分支循环
if语句
1,单分支结构;
if 条件 ; then
.....
fi
--(如果then和 条件在同一行,则中间必须有分号;)
2,双分支结构
if 条件; then
.....
else
.....
fi
3,多分支结构
if 条件 ;then
.....
elif 条件 ; then
.....
else
......
fi
case语句
case分支语句的格式如下:
case $变量名 in
模式1)
命令序列1
;;
模式2)
命令序列2
;;
*)
默认执行的命令序列 ;;
esac
case语句结构特点如下:
case行尾必须为单词“in”,每一个模式必须以右括号“)”结束。
双分号“;;”表示命令序列结束。
匹配模式中可是使用方括号表示一个连续的范围,如[0-9];使用竖杠符号“|”表示或。
最后的“*)”表示默认模式,当使用前面的各种模式均无法匹配该变量时,将执行“*)”后
的命令序列。
例如;
read a
case "$a" in
1) echo "输入为1"
;;
2)echo "输入为2"
;;
[3-9])echo "输入为3-9"
;;
11 | 12) echo "输入为11或12"
*)echo "输入为其它"
esac
while循环
语法;
while 条件
do
.....
done
解释;
条件满足则一直做
例如;
while true --死循环
do
uptime --可以看系统时间,用户系统负载
sleep 2
done
for循环
1》语法;
for 变量名 in 变量取值列表
do
........
done
说明;
其中 “in 变量取值列表” 可省略,
如果省略可相当于 for 变量名 in "$@" 即从所有的命令行参数中取值
解释;
即变量依次被赋值成取值列表中的值
然后去执行后面的语句
2》语法;
for 变量名 in {5..1} ----使用 for 变量名 in `seq -s " " 5 -1 1`
do
......
done
解释;
{5..1}表示,为序列,从5到1,
{a..z}表字,26个英文字母的序列
3》语法;(说明,ksh不支持此种语法)
for ((exp1;exp2;exp3))
do
.....
done
解释;
语法和C的for语法一样
例如 ;
for((i=0;i<=9;i++))
do
echo $i
done
例如;
打印出5 4 3 2 1
for num in 5 4 3 2 1
do
echo $num
done
例如;则打印出来的全是目录
for i in `ls -F|grep /`
do
echo $i
done
seq的用法;
1>> seq -选项 LAST
2>> seq -选项 FIRST LAST
3>> seq -选项 FIRST INCREMENT LAST
例如;
seq 5
seq 1 5
seq 1 2 10 ---中间数字表示步长,,步长可以是小数(例如;seq 1 0.1 10)
seq 10 -2 1 ---返向,数字表示步长,负号表示减少
选项;
-w 指定输出数字同宽
-s 指定分隔符
-f 指定格式
例;
seq -w 10
结果是;
01
02
。。。
10
seq -s "-" 10
结果是; 1-2-3-。。。-10
seq -f "%3g" 1 100
结果是;
1
2
。。。
20
。。。
100
seq -f "str%g" 10
结果是;
str1
str2
..
str10
退出分支或程序
break,continue,exit用法;
break ----结束循环体,向下执行
continue---路过本次循环,去执行done,再判断
exit----退出程序
十二、函数
函数名(){ 。。。。 。。。。。 return n } |
或者 function 函数名(){ 。。。。 。。。。。 return n }
|
调用方式:
1》直接用函数名就好了,
函数名
---不需要带()
---定义时没有参数 ,但调用时,是可以带参数的
2》带参数函数的调用
函数名 参数1 参数2 (和脚本命令行带参数一样)
获取函数返回值
方法1:使用return 返回时 check_count () { 略。。。。。。。 return $sum_count } ##执行函数 check_count #获取函数返回值 a=`echo $?` |
方法2:使用echo方法 nowtime() { echo `date +"[%Y-%m-%d %H:%M]"` }
##获取当前时间 now_time=`nowtime` |
十三、数组
下标从0开始
1,数组的定义
数组名=(value1 value2 value3 value4...)
echo ${#数组名[@]}
echo ${#数组名[*]}
--以上都可获取数组长度
echo ${数组名[0]}
---取数组中第1个元素
echo ${数组名[*]}
echo ${数组名[@]}
----遍历打印数组
2,数组的赋值
数组名[0]=4
----给第数组中第1个元素赋值成4
数组名[6]=8
---如果数组长度小于7,则此时相当于增加数组元素,
3,数组元素的删除
unset 数组名[0]
---删除数组中第1个元素
unset 数组名
---删除整个数组
4,数组元素的替换
因为数组也算是变量的一种,所以它也适用于变量字符串的一些操作
例如;
arr=(1 2 3 4 5)
echo ${arr[@]:1:3} ---截取下标为1到3的元素
echo ${arr[@]/5/6} ---让数组的值为5的元素,换成6
十四、find命令
格式;
find 路径 - 选项 【-print -exec -ok】
选项:
-name "....." 按文件名查找
-type
f 普通文件
d 目录
b 块设备
c 字符设备
p 管道设备
l 链接文件
-depth
在查找文件时,首先查找当前目录中的文件,然后再在其子目录中查找。
参数:
-print: find命令将匹配的文件输出到标准输出。
-exec: find命令对匹配的文件执行该参数所给出的shell命令。
相应命令的形式为'command' { } \;
注意{ }和\;之间的空格。
-ok: 和-exec的作用相同,在执行每一个命令之前,都会给出提示,让用户来确定是否执行。
find 和 exec配合
1,
# find . -type f -exec ls -l { } \;
-rw-r--r-- 1 root root 34928 2003-02-25 ./conf/httpd.conf
-rw-r--r-- 1 root root 12959 2003-02-25 ./conf/magic
-rw-r--r-- 1 root root 180 2003-02-25 ./conf.d/README
---find命令匹配到了当前目录下的所有普通文件,并在-exec选项中使用ls -l命令将它们列出
2,
find logs -type f -mtime +5 -exec rm { } \;
---在/logs目录中查找更改时间在5日以前的文件并删除它们
3,
find . -name "*.conf" -mtime +5 -ok rm { } \;
< rm ... ./conf/httpd.conf > n
--find命令在当前目录中查找所有文件名以.LOG结尾、更改时间在5日以上的文件,
---并删除它们,只不过在删除之前先给出提示。
--按y键删除文件,按n键不删除。
4,
find /etc -name "passwd*" -exec grep "sam" { } \;
sam:x:501:501::/usr/sam:/bin/bash
--find命令首先匹配所有文件名为“ passwd*”的文件,
--例如passwd、passwd.old、passwd.bak,
---然后执行grep命令看看在这些文件中是否存在一个sam用户
find命令和xargs命令配合
1,
#find . -type f -print | xargs file
--查找系统中的每一个普通文件,然后使用xargs命令来测试它们分别属于哪类文件
2,
$ find / -name "core" -print | xargs echo "" >/tmp/core.log
--在整个系统中查找内存信息转储文件(core dump) ,然后把结果保存到/tmp/core.log 文件中
3,
# find . -type f -print | xargs grep "hostname"
--用grep命令在所有的普通文件中搜索hostname这个词:
总结;
find命令配合使用exec和xargs可以使用户对所匹配到的文件执行几乎所有的命令。
十五、xargs命令
-0 |
当sdtin含有特殊字元时候,将其当成一般字符,想/'空格等 |
|
例如:root@localhost:~/test#echo "//"|xargs echo |
|
root@localhost:~/test#echo "//"|xargs -0 echo |
|
|
-a |
file 从文件中读入作为sdtin,(看例一) |
-e |
flag ,注意有的时候可能会是-E,flag必须是一个以空格分隔的标志,当xargs分析到含有flag这个标志的时候就停止 |
-p |
当每次执行一个argument的时候询问一次用户。(例三) |
-n |
num 后面加次数,表示命令在执行的时候一次用的argument的个数,默认是用所有的。(例四) |
-t |
表示先打印命令,然后再执行。(例五) |
-i |
或者是-I,这得看linux支持了,将xargs的每项名称,一般是一行一行赋值给{},可以用{}代替。(例六) |
-r |
no-run-if-empty 当xargs的输入为空的时候则停止xargs,不用再去执行了。(例七) |
-s |
num 命令行的最好字符数,指的是xargs后面那个命令的最大命令行字符数。(例八) |
|
|
-L |
num Use at most max-lines nonblank input lines per command line.-s是含有空格的。 |
-l |
同-L |
-d |
delim 分隔符,默认的xargs分隔符是回车,argument的分隔符是空格,这里修改的是xargs的分隔符(例九) |
-x |
exit的意思,主要是配合-s使用。 |
-P |
修改最大的进程数,默认是1,为0时候为as many as it can ,这个例子我没有想到,应该平时都用不到的吧。 |
定义一个测试文件,内有多行文本数据:
|
-n 选项,指定几行内容,分割成一小块, |
|
|
以下是-i 和 -I 的区别 ,-I (即大写的),可以指定xargs扩展时,把什么字符替换掉,替换成输入的内容。 -i (即小写的),默认是把{} 这个字符串替换成输入的内容。 |
|
|
十六、sort命令
原理;
sort将文件的每一行作为一个单位,相互比较,
比较原则是比较首字符,按ASCII码值进行比较,
最后默认将他们按升序输出。
-u 排序后去重
-r 逆序排(降序)
-o 原文件名 排完序后,将内容更新到原文件,
(原内容将会被清空,使用重定向符到原文件时,则会清空原文件)
-n 以数值作比较(而非以首字符)
-t 间隔符
-k 列数 比较每一行中,指定的列的首字符 (而非每一行中首字符)
-b 忽略前面一行中的所有空白部分,从第一个可见字符进行比较
举例:
[root@Fedora6 huang]# ls |sort -t . -k 1 -n -r
111111111111.txt
33312.txt
2.txt
1.txt
[root@Fedora6 huang]# ls |sort -t . -k 1 -r
33312.txt
2.txt
1.txt
111111111111.txt
sort 去重
1,假如有文件1.txt
2,则排重后
十一、awk编程
优点
解决了cut命令不能很好识别 空格作为分隔符的列的不足
解决了printf不能很好的格式输出的不足
它可以识别任何作为分隔符的列(例: 分号,空格 ,TAB,)
它比较复杂,它不仅可以进行字符串的截取,也可以进行函数调用,判断,流程控制
由于以上原因,一般也叫做awk编程
它默认也是空格作为分隔符的
语法
awk -F 分隔符 '条件1{动作1}条件2{动作2}。。。' 文件名
注意:
不写条件,默认条件值为1
BEGIN, END 也是条件,(一个是在遍历文件前,一个是在遍历文件后)
内部变量
|
例:
awk 'END{print NR}' 1.txt --可以打印出文件中有多少行
杂项
FS 用法:
(相当于在命令行模式下使用-F 指定分隔符)
例;
awk -F ":" '{print $1}' --命令行模式
{BEGIN{FS=":"}{print $1}} --放在文件中的写法
初始化(即未定义时的默认值)
字符串变量初始化为空字符串""
数值变量初始化为0
print 和 printf
print --自动在应该输出的每行后面加个\n,没有格式化控制输出
printf --不会换行(需要人为加\n),它可以有格式化控制输出
1,普通模式:
awk '/pattern/{action}' files
patter ---是一个正则表达式, (如果不指定pattern,则对所有文件的每一行都执行action)
action ----又是一系列命令
files ------表示待操作的文件 (如果不指定,则输入是STDIN。)
2,表达式模式
awk '(expression){action}' files
awk '(expr1) && (expr2) {action}' files
awk '(expr1) || (expr2) {action}' files
expression --是一个比较表达式,也可以是复合表达式
其它同上。
#awk 都是以文本中一行一行的进行操作处理的。每处理一行,进行除了BEGIN和END语句之外的操作
#$0 表示整行(以本行本来的面目显示)
#awk '{print $0}'
#awk 如果后面没有跟文件由默认是STDIN 等待输入
3,文件模式:
即写在 ’ ’ 中的命令,也可以单独写在文件中
比较操作
awk中可以执行的比较操作有
<
>
<=
>=
!=
awk '($2>3){print $1,$3}' --当第2列值大于3时,指印出指定内容
awk '($2>3)&&($2<5){print $1,$3}' --当第2列>3且<5时打印出指定内容
awk '($2<5){print $1,$3};($2>5){print $2}' --当$2>5 打印$2 ; 当$2<5打印 $1 $3
BEGING和END
二者都不参于文本中每行的处理,只是做此初始化和善后的工作;
二者必须大写
基本语法:
awk '
BEGIN { actions }
/pattern/ { actions }
/pattern/ { actions }
END { actions }
' files
说明:
多个{}之间,可以略去分号;也可以不省略。
流控制(if while for)
将流控制语句放在{}执行块中
if(表达式) #if ( Variable in Array )
如果你为了方便Unix awk判断也方便你自已阅读,你最好将多个语句用{}括起来 |
if(表达式) {语句1} else if(表达式)
|
1.while语句 格式: while(表达式) {语句}
|
|
for循环有两种格式: 格式1: for(变量 in 数组) {语句} 例: for(k in ENVIRON) |
格式2: for(变量;条件;表达式) {语句} 例: for(i=0;i<=100;i++) |
变量的应用举例
ps -ef|grep -v grep |grep puaf01|grep -E "nosi_monitor|run_fts|run_pps|run_shm|run_bps|run_stat|run_unt|run_exp|md5|" > 1.txt
cat 1.txt|awk '\
BEGIN {fts_count=0;pps_count=0;shm_count=0;bps_count=0;stat_count=0;unt_count=0;exp_count=0;md5_count=0};\
\
{if ($0 ~ /.*run_fts.*/) {fts_count += 1} \
if ($0 ~ /.*run_pps.*/) {pps_count += 1}\
if ($0 ~ /.*run_shm.*/) {shm_count += 1}\
if ($0 ~ /.*run_bps.*/) {bps_count += 1}\
if ($0 ~ /.*run_stat.*/) {stat_count += 1}\
if ($0 ~ /.*run_unt.*/) {unt_count += 1}\
if ($0 ~ /.*run_exp.*/) {exp_count += 1}\
if ($0 ~ /.*md5.*/) {md5_count += 1}};\
\
END {printf("fts=%s,\npps=%s,\nshm=%s,\nbps=%s,\nstat=%s,\nunt=%s,\nexp=%s,\nmd5=%s\n"),\
fts_count,pps_count,shm_count,bps_count,stat_count,unt_count,exp_count,md5_count}'
调用外部命令举例
1,将当前目录 下的面文件取模,依次MV到对应的目录下面
ls |awk -F "_" '{print $(NF-1),$(NF-1)%3,$0};\
{\
if($(NF-1)%3==0){cmd="mv "$0 " ../dir1";system(cmd)}\
if($(NF-1)%3==1){cmd="mv "$0 " ../dir2";system(cmd)}\
if($(NF-1)%3==2){cmd="mv "$0 " ../dir3";system(cmd)}\
\
}; END{a="file_count:";print a" "NR}'\
## 注:以上要在字符串中解析出$0,必须将$0写在引号外
2,去不同的目录下面,将文件备份到一个文件夹中
cd /uniocs/users/Billapp/csdata/gsm;
ls | xargs -n1 -i echo "/uniocs/users/Billapp/csdata/gsm/{}" | awk '{cmd="mv "$0"* ../gsm_bak_test";print cmd;system(cmd)}'
传递外部变量到AWK
语法:
awk -v 变量=$SHELL中的变量 ‘{ 语句块 }’
例子:
AWK去重
语法:
awk '!(a[$0]++)' 文件
首先准备一个文本文件,随便写个文件,包含重复行数据的即可,或者你可以参考我这里的文件:
CodingAnts@ubuntu:~/awk$ cat dup
hello world
awk
coding ants
hello world
awk
hello world
awk
coding ants
coding ants
共有9行,后面6行都是重复的前面的几行,最终的效果应该是只显示上面重点显示的那几行,先来看看效果:
CodingAnts@ubuntu:~/awk$ awk '!(a[$0]++)' dup
hello world
awk
coding ants
原理:
awk的程序指令由模式和操作组成,即Pattern { Action }的形式,如果省略Action,则默认执行 print $0 的操作。
实现去除重复功能的就是这里的Pattern: !(a[$0]++)
步骤:
1,在awk中,对于未初始化的数组变量,在进行数值运算的时候,会赋予初值0,因此a[$0]=0,++运算符的特性是先取值,后加1,因此Pattern等价于!0
2,而0为假,!为取反,因此整个Pattern最后的结果为1,相当于if(1),Pattern匹配成功,输出当前记录,对于dup文件,前3条记录的处理方式都是如此。
3,当读取第4行数据“hello world”的时候,a[$0]=1,取反后的结果为0,即Pattern为0,Pattern匹配失败,因此不输出这条记录,后续的数据以此类推,最终成功实现去除文件中的重复行。
--------=====--------