ip link显示的数据来源
# ll /sys/class/net
lrwxrwxrwx 1 root root 0 Aug 24 10:02 ens3 -> ../../devices/pci0000:00/0000:00:03.0/virtio0/net/ens3
lrwxrwxrwx 1 root root 0 Aug 24 10:02 ovs-system -> ../../devices/virtual/net/ovs-system
# ip link show up
3: ens4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT qlen 1000
4: ovs-system: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN mode DEFAULT qlen 1000
# grep 3 -rs `pwd`/ens4
/sys/class/net/ens4/iflink:3
/sys/class/net/ens4/address:fa:16:3e:75:d9:b3
/sys/class/net/ens4/uevent:IFINDEX=3
/sys/class/net/ens4/ifindex:3
最近为方便运维通过脚本完成私有云集群大网迁移,学习下shell编程
shell编程进阶:https://www.cnblogs.com/clsn/p/8028337.html#auto_id_40
shell中的if语句
1、基本语法:
if [ command ]; then 符合该条件执行的语句 fi
2、扩展语法:
if [ command ];then 符合该条件执行的语句 elif [ command ];then 符合该条件执行的语句 else 符合该条件执行的语句 fi
3、语法说明:
bash shell会按顺序执行if语句,如果command执行后且它的返回状态是0,则会执行符合该条件执行的语句,否则后面的命令不执行,跳到下一条命令。
当有多个嵌套时,只有第一个返回0退出状态的命令会导致符合该条件执行的语句部分被执行,如果所有的语句的执行状态都不为0,则执行else中语句。
返回状态:最后一个命令的退出状态,或者当没有条件是真的话为0。
注意:
1、[ ]表示条件测试。注意这里的空格很重要。要注意在'['后面和']'前面都必须要有空格 2、在shell中,then和fi是分开的语句。如果要在同一行里面输入,则需要用分号将他们隔开。 3、注意if判断中对于变量的处理,需要加引号,以免一些不必要的错误。没有加双引号会在一些含空格等的字符串变量判断的时候产生错误。比如[ -n "$var" ]如果var为空会出错 4、判断是不支持浮点值的 5、如果只单独使用>或者<号,系统会认为是输出或者输入重定向,虽然结果显示正确,但是其实是错误的,因此要对这些符号进行转意 6、在默认中,运行if语句中的命令所产生的错误信息仍然出现在脚本的输出结果中 7、使用-z或者-n来检查长度的时候,没有定义的变量也为0 8、空变量和没有初始化的变量可能会对shell脚本测试产生灾难性的影响,因此在不确定变量的内容的时候,在测试号前使用-n或者-z测试一下 9、? 变量包含了之前执行命令的退出状态(最近完成的前台进程)(可以用于检测退出状态)
常用参数:
文件/目录判断:
[ -a FILE ] 如果 FILE 存在则为真。
[ -d FILE ] 如果 FILE 存在且是一个目录则返回为真。
[ -e FILE ] 如果 指定的文件或目录存在时返回为真。
[ -f FILE ] 如果 FILE 存在且是一个普通文件则返回为真。
[ -r FILE ] 如果 FILE 存在且是可读的则返回为真。
[ -w FILE ] 如果 FILE 存在且是可写的则返回为真。(一个目录为了它的内容被访问必然是可执行的)
[ -x FILE ] 如果 FILE 存在且是可执行的则返回为真。
不常用的:
[ -b FILE ] 如果 FILE 存在且是一个块文件则返回为真。
[ -c FILE ] 如果 FILE 存在且是一个字符文件则返回为真。
[ -g FILE ] 如果 FILE 存在且设置了SGID则返回为真。
[ -h FILE ] 如果 FILE 存在且是一个符号符号链接文件则返回为真。(该选项在一些老系统上无效)
[ -k FILE ] 如果 FILE 存在且已经设置了冒险位则返回为真。
[ -p FILE ] 如果 FILE 存并且是命令管道时返回为真。
[ -s FILE ] 如果 FILE 存在且大小非0时为真则返回为真。
[ -u FILE ] 如果 FILE 存在且设置了SUID位时返回为真。
[ -O FILE ] 如果 FILE 存在且属有效用户ID则返回为真。
[ -G FILE ] 如果 FILE 存在且默认组为当前组则返回为真。(只检查系统默认组)
[ -L FILE ] 如果 FILE 存在且是一个符号连接则返回为真。
[ -N FILE ] 如果 FILE 存在 and has been mod如果ied since it was last read则返回为真。
[ -S FILE ] 如果 FILE 存在且是一个套接字则返回为真。
[ FILE1 -nt FILE2 ] 如果 FILE1 比 FILE2 新, 或者 FILE1 存在但是 FILE2 不存在则返回为真。
[ FILE1 -ot FILE2 ] 如果 FILE1 比 FILE2 老, 或者 FILE2 存在但是 FILE1 不存在则返回为真。
[ FILE1 -ef FILE2 ] 如果 FILE1 和 FILE2 指向相同的设备和节点号则返回为真。
字符串判断
[ -z STRING ] 如果STRING的长度为零则返回为真,即空是真 [ -n STRING ] 如果STRING的长度非零则返回为真,即非空是真 [ STRING1 ] 如果字符串不为空则返回为真,与-n类似 [ STRING1 == STRING2 ] 如果两个字符串相同则返回为真 [ STRING1 != STRING2 ] 如果字符串不相同则返回为真 [ STRING1 < STRING2 ] 如果 “STRING1”字典排序在“STRING2”前面则返回为真。 [ STRING1 > STRING2 ] 如果 “STRING1”字典排序在“STRING2”后面则返回为真。
数值判断
[ INT1 -eq INT2 ] INT1和INT2两数相等返回为真 ,= [ INT1 -ne INT2 ] INT1和INT2两数不等返回为真 ,<> [ INT1 -gt INT2 ] INT1大于INT2返回为真 ,> [ INT1 -ge INT2 ] INT1大于等于INT2返回为真,>= [ INT1 -lt INT2 ] INT1小于INT2返回为真 ,< [ INT1 -le INT2 ] INT1小于等于INT2返回为真,<=
逻辑判断
[ ! EXPR ] 逻辑非,如果 EXPR 是false则返回为真。 [ EXPR1 -a EXPR2 ] 逻辑与,如果 EXPR1 and EXPR2 全真则返回为真。 [ EXPR1 -o EXPR2 ] 逻辑或,如果 EXPR1 或者 EXPR2 为真则返回为真。 [ ] || [ ] 用OR来合并两个条件 [ ] && [ ] 用AND来合并两个条件
其他判断
[ -t FD ] 如果文件描述符 FD (默认值为1)打开且指向一个终端则返回为真 [ -o optionname ] 如果shell选项optionname开启则返回为真
IF高级特性:
双圆括号(( )):表示数学表达式
在判断命令中只允许在比较中进行简单的算术操作,而双圆括号提供更多的数学符号,而且在双圆括号里面的'>','<'号不需要转意。
双方括号[[ ]]:表示高级字符串处理函数
双方括号中判断命令使用标准的字符串比较,还可以使用匹配模式,从而定义与字符串相匹配的正则表达式。
双括号的作用:
在shell中,[ $a != 1 || $b = 2 ]是不允许出,要用[ $a != 1 ] || [ $b = 2 ],而双括号就可以解决这个问题的,[[ $a != 1 || $b = 2 ]]。又比如这个[ "$a" -lt "$b" ],也可以改成双括号的形式(("$a"
< "$b"))
实例
1:判断目录$doiido是否存在,若不存在,则新建一个
if [ ! -d "$doiido"]; then mkdir "$doiido" fi
2:判断普通文件$doiido是否存,若不存在,则新建一个
if [ ! -f "$doiido" ]; then touch "$doiido" fi
3:判断$doiido是否存在并且是否具有可执行权限
if [ ! -x "$doiido"]; then mkdir "$doiido" chmod +x "$doiido" fi
4:是判断变量$doiido是否有值
if [ ! -n "$doiido" ]; then echo "$doiido is empty" exit 0 fi
5:两个变量判断是否相等
if [ "$var1" = "$var2" ]; then echo '$var1 eq $var2' else echo '$var1 not eq $var2' fi
6:测试退出状态:
if [ $? -eq 0 ];then echo 'That is ok' fi
7:数值的比较:
if [ "$num" -gt "150" ];then echo "$num is biger than 150" fi
8:a>b且a<c
(( a > b )) && (( a < c )) [[ $a > $b ]] && [[ $a < $c ]] [ $a -gt $b -a $a -lt $c ]
9:a>b或a<c
(( a > b )) || (( a < c )) [[ $a > $b ]] || [[ $a < $c ]] [ $a -gt $b -o $a -lt $c ]
10:检测执行脚本的用户
if [ "$(whoami)" != 'root' ]; then echo "You have no permission to run $0 as non-root user." exit 1; fi
上面的语句也可以使用以下的精简语句
[ "$(whoami)" != 'root' ] && ( echo "You have no permission to run $0 as non-root user."; exit 1 )
11:正则表达式
doiido="hero" if [[ "$doiido" == h* ]];then echo "hello,hero" fi
============其他例子============
1、查看当前操作系统类型
#!/bin/sh SYSTEM=`uname -s` if [ $SYSTEM = "Linux" ] ; then echo "Linux" elif [ $SYSTEM = "FreeBSD" ] ; then echo "FreeBSD" elif [ $SYSTEM = "Solaris" ] ; then echo "Solaris" else echo "What?" fi
2、if利用read传参判断
#!/bin/bash read -p "please input a score:" score echo -e "your score [$score] is judging by sys now" if [ "$score" -ge "0" ]&&[ "$score" -lt "60" ];then echo "sorry,you are lost!" elif [ "$score" -ge "60" ]&&[ "$score" -lt "85" ];then echo "just soso!" elif [ "$score" -le "100" ]&&[ "$score" -ge "85" ];then echo "good job!" else echo "input score is wrong , the range is [0-100]!" fi
3、判断文件是否存在
#!/bin/sh today=`date -d yesterday +%y%m%d` file="apache_$today.tar.gz" cd /home/chenshuo/shell if [ -f "$file" ];then echo “”OK" else echo "error $file" >error.log mail -s "fail backup from test" loveyasxn924@126.com <error.log fi
4、这个脚本在每个星期天由cron来执行。如果星期的数是偶数,他就提醒你把垃圾箱清理:
#!/bin/bash WEEKOFFSET=$[ $(date +"%V") % 2 ] if [ $WEEKOFFSET -eq "0" ]; then echo "Sunday evening, put out the garbage cans." | mail -s "Garbage cans out" your@your_domain.org fi
5、挂载硬盘脚本(windows下的ntfs格式硬盘)
#! /bin/sh dir_d=/media/disk_d dir_e=/media/disk_e dir_f=/media/disk_f a=`ls $dir_d | wc -l` b=`ls $dir_e | wc -l` c=`ls $dir_f | wc -l` echo "checking disk_d..." if [ $a -eq 0 ]; then echo "disk_d is not exsit,now creating..." sudo mount -t ntfs /dev/disk/by-label/software /media/disk_d else echo "disk_d exits" fi
echo "checking disk_e..." if [ $b -eq 0 ]; then echo "disk_e is not exsit,now creating..." sudo mount -t ntfs /dev/disk/by-label/elitor /media/disk_e else echo "disk_e exits" fi echo "checking disk_f..." if [ $c -eq 0 ]; then echo "disk_f is not exsit,now creating..." sudo mount -t ntfs /dev/disk/by-label/work /media/disk_f else echo "disk_f exits" fi
((i=$j+$k)) 等价于 i=`expr $j + $k`
((i=$j-$k)) 等价于 i=`expr $j -$k`
((i=$j*$k)) 等价于 i=`expr $j \*$k`
((i=$j/$k)) 等价于 i=`expr $j /$k`
Let expressions 执行一个或多个表达式。表达式中的变量前不必有$.如果表达式中包含了空格或其他特殊字符,则必须引起来。
例:let “I = I + 1” 或 let i=i+1
算术运算符指的是可以在程序中实现加、减、乘、除等数学运算的运算符。Shell中常用的数学运算符如下所示。
— +:对两个变量做加法。
— -:对两个变量做减法。
— *:对两个变量做乘法。
— /:对两个变量做除法。
— **:对两个变量做幂运算。
— %:取模运算,第一个变量除以第二个变量求余数。
— +=:加等于,在自身基础上加第二个变量。
— -=:减等于,在第一个变量的基础上减去第二个变量。
— *=:乘等于,在第一个变量的基础上乘以第二个变量。
— /=:除等于,在第一个变量的基础上除以第二个变量。
— %=:取模赋值,第一个变量对第二个变量取模运算,再赋值给第一个变量。
在使用这些运算符时,需要注意到运算顺序的问题。例如输入下面的命令,输出1+2的结果。
echo 1+2
Shell并没有输出结果3,而是输出了1+2。在shell中有三种方法可以更改运算顺序。
— 用expr改变运算顺序。可以用echo `expr 1 +2`来输出1+2的结果,用expr表示后面的表达式为一个数学运算。需要注意的是,`并不是一个单引号,而是“Tab”键上面的那个符号。
— 用let指示数学运算。可以先将运算的结果赋值给变量b,运算命令是b=let 1 + 2。然后用echo$b来输出b的值。如果没有let,则会输出1+2。
— 用$[]表示数学运算。将一个数学运算写到$[]符号的中括号中,中括号中的内容将先进行数学运算。例如命令echo$[1+2],将输出结果3。
下面是一个shell程序实例,实现数学函数S=3(xy)+4x2+5y+6的运算。在程序中以位置变量的方式输入x与y的值。程序的编写步骤如下所示。
在主菜单中打开一个终端。在终端中输入“vim”命令打开VIM。
在VIM中按“i”键进入插入模式,然后输入下面的代码。
代码4-2 数学运算实例:\源文件\04\4.4.sh
#!/bin/bash
#4.4.sh
s=0 #定义一个求和变量,初值为0。
t=`expr$1**$2` #用expr改变运算顺序,求x的y次方。
t=$[t*3] #t乘以3。
s=$[s+t] #结果相加。
t=$[$1**2] #求x的平方。
t=$[t*4] #结果乘以4。
s=$[s+t] #结果相加。
t=`expr$2*5` #求5y的值。
s=$[s+t] #结果相加。
s=$[s+6] #结果加上6。
echo$s #输出结果。
echo$((a%b)) #取余
在这个程序中,需要注意算术运算的写法。如果没有expr或$[]更改运算顺序,则会将运算式以字符串的形式赋值,而不会赋值运算结果。
按“Esc”键返回到普通模式。然后输入“:w 4.4.sh”保存文件。
输入“:q”命令,按“Enter”键退出VIM。
在终端中,输入下面的命令对4.4.sh文件添加可执行权限。
chmod +x 4.4.sh
输入下面的命令运行程序。在命令中需要输入两个参数。
./4.4.sh 2 4
程序会完成S=3(xy)+4x2+5y+6的数学运算并输出结果,结果如下所示。
shell条件判断if中的-a到-z的意思
[ -a FILE ] 如果 FILE 存在则为真。
[ -b FILE ] 如果 FILE 存在且是一个块特殊文件则为真。
[ -c FILE ] 如果 FILE 存在且是一个字特殊文件则为真。
[ -d FILE ] 如果 FILE 存在且是一个目录则为真。
[ -e FILE ] 如果 FILE 存在则为真。
[ -f FILE ] 如果 FILE 存在且是一个普通文件则为真。
[ -g FILE ] 如果 FILE 存在且已经设置了SGID则为真。 [ -h FILE ] 如果 FILE 存在且是一个符号连接则为真。
[ -k FILE ] 如果 FILE 存在且已经设置了粘制位则为真。
[ -p FILE ] 如果 FILE 存在且是一个名字管道(F如果O)则为真。
[ -r FILE ] 如果 FILE 存在且是可读的则为真。
[ -s FILE ] 如果 FILE 存在且大小不为0则为真。
[ -t FD ] 如果文件描述符 FD 打开且指向一个终端则为真。
[ -u FILE ] 如果 FILE 存在且设置了SUID (set user ID)则为真。
[ -w FILE ] 如果 FILE 如果 FILE 存在且是可写的则为真。
[ -x FILE ] 如果 FILE 存在且是可执行的则为真。
[ -O FILE ] 如果 FILE 存在且属有效用户ID则为真。
[ -G FILE ] 如果 FILE 存在且属有效用户组则为真。
[ -L FILE ] 如果 FILE 存在且是一个符号连接则为真。
[ -N FILE ] 如果 FILE 存在 and has been mod如果ied since it was last read则为真。
[ -S FILE ] 如果 FILE 存在且是一个套接字则为真。
[ FILE1 -nt FILE2 ] 如果 FILE1 has been changed more recently than FILE2, or 如果 FILE1 exists and FILE2 does not则为真。
[ FILE1 -ot FILE2 ] 如果 FILE1 比 FILE2 要老, 或者 FILE2 存在且 FILE1 不存在则为真。
[ FILE1 -ef FILE2 ] 如果 FILE1 和 FILE2 指向相同的设备和节点号则为真。
[ -o OPTIONNAME ] 如果 shell选项 “OPTIONNAME” 开启则为真。
[ -z STRING ] “STRING” 的长度为零则为真。
[ -n STRING ] or [ STRING ] “STRING” 的长度为非零 non-zero则为真。
[ STRING1 == STRING2 ] 如果2个字符串相同。 “=” may be used instead of “==” for strict POSIX compliance则为真。
[ STRING1 != STRING2 ] 如果字符串不相等则为真。
[ STRING1 < STRING2 ] 如果 “STRING1” sorts before “STRING2” lexicographically in the current locale则为真。
[ STRING1 > STRING2 ] 如果 “STRING1” sorts after “STRING2” lexicographically in the current locale则为真。
[ ARG1 OP ARG2 ] “OP” is one of -eq, -ne, -lt, -le, -gt or -ge. These arithmetic binary operators return true if “ARG1” is equal to, not equal to, less than, less than or equal to, greater than, or greater than or equal to “ARG2”, respectively. “ARG1” and “ARG2” are integers.
=====================================================================
基本上和其他脚本语言一样。没有太大区别。不过值得注意的是。[]里面的条件判断。
1、字符串判断
str1 = str2 当两个串有相同内容、长度时为真
str1 != str2 当串str1和str2不等时为真
-n str1 当串的长度大于0时为真(串非空)
-z str1 当串的长度为0时为真(空串)
str1 当串str1为非空时为真
2、数字的判断
int1 -eq int2 两数相等为真
int1 -ne int2 两数不等为真
int1 -gt int2 int1大于int2为真
int1 -ge int2 int1大于等于int2为真
int1 -lt int2 int1小于int2为真
int1 -le int2 int1小于等于int2为真
3、文件的判断
-r file 用户可读为真
-w file 用户可写为真
-x file 用户可执行为真
-f file 文件为正规文件为真
-d file 文件为目录为真
-c file 文件为字符特殊文件为真
-b file 文件为块特殊文件为真
-s file 文件大小非0时为真
-t file 当文件描述符(默认为1)指定的设备为终端时为真
4、复杂逻辑判断
-a 与
-o 或
! 非
shell高级学习之正则表达式
更新时间:2019年05月31日 08:35:21 作者:秦广王 我要评论
正则表达式概述
正则表达式是一种定义的规则,Linux工具可以用它来过滤文本。
基础正则表达式
纯文本
1
2
3
4
|
[root@node1 ~] # echo "this is a cat" | sed -n '/cat/p' this is a cat [root@node1 ~] # echo "this is a cat" | gawk '/cat/{print $0}' this is a cat |
正则表达式的匹配非常挑剔,尤其需要记住,正则表达式区分大小写。
特殊字符
正则表达式识别的特殊字符包括:
.*[]^${}\+?|()
如果要使用某个特殊字符作为文本字符,就必须转义,一般用(\)来转义。
1
2
|
[root@node1 ~] # echo "this is a $" | sed -n '/\$/p' this is a $ |
锚字符
有两个特殊字符可以用来将模式锁定在数据流的行首或行尾
脱字符(^)定义从数据流中文本行的行首开始的模式。
美元符($)定义了行尾锚点。
1
2
3
4
|
[root@node1 ~] # echo "this is a cat" | sed -n '/^this/p' this is a cat [root@node1 ~] # echo "this is a cat" | sed -n '/cat$/p' this is a cat |
在一些情况下可以组合使用这两个命令
1.比如查找只含有特定文本的行
1
2
3
4
5
6
7
8
9
|
[root@node1 ljy] # more test.txt this is a dog what how this is a cat is a dog [root@node1 ljy] # sed -n '/^is a dog$/p' test.txt is a dog [root@node |
2.两个锚点组合起来,可以直接过滤空白行
1
2
3
4
5
6
7
8
9
10
11
12
13
|
[root@node1 ljy] # more test.txt this is a dog what how this is a cat is a dog [root@node1 ljy] # sed '/^$/d' test.txt this is a dog what how this is a cat is a dog |
点号字符
点号用来匹配除换行符外的任意单个字符,他必须匹配一个字符。
1
2
3
4
5
6
7
8
9
10
|
[root@node1 ljy] # more test.txt this is a dog what how this is a cat is a dog at [root@node1 ljy] # sed -n '/.at/p' test.txt what this is a cat |
字符组
限定待匹配的具体字符,使用字符组。使用方括号来定义一个字符组。
1
2
3
4
5
6
7
8
9
10
11
12
|
[root@node1 ljy] # more test.txt this is a dog this is a Dog this is a DoG this is a cat [root@node1 ljy] # sed -n '/[dD]og/p' test.txt this is a dog this is a Dog [root@node1 ljy] # sed -n '/[dD]o[gG]/p' test.txt this is a dog this is a Dog this is a DoG |
排除型字符组
要排除某些特定的元素,要在字符组前面加个脱字符。
1
2
3
4
5
6
|
[root@node1 ljy] # sed -n '/[dD]o[gG]/p' test.txt this is a dog this is a Dog this is a DoG [root@node1 ljy] # sed -n '/[^D]og/p' test.txt this is a dog |
区间
正则表达式会包括此区间内的任意字符。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
[root@node1 ljy] # more test.txt 123123 1231 121222222 412345341613 vsdvs qwer12344123 12345 34211 444444 [root@node1 ljy] # sed -n '/^[0-9][0-9][0-9][0-9][0-9]$/p' test.txt 12345 34211 |
拓展正则表达式
问号
问号表明前面的字符出现0次或者1次,仅限于此。
1
2
3
4
5
|
[root@node1 ljy] # echo "bat" | gawk '/ba?t/{print $0}' bat [root@node1 ljy] # echo "baat" | gawk '/ba?t/{print $0}' [root@node1 ljy] # echo "bt" | gawk '/ba?t/{print $0}' bt |
可以将问号和字符组一起使用
1
2
3
4
5
6
7
|
[root@node1 ljy] # echo "bt" | gawk '/b[ae]?t/{print $0}' bt [root@node1 ljy] # echo "bat" | gawk '/b[ae]?t/{print $0}' bat [root@node1 ljy] # echo "bet" | gawk '/b[ae]?t/{print $0}' bet [root@node1 ljy] # echo "baat" | gawk '/b[ae]?t/{print $0}' |
加号
加号表明前面的字符可以出现一次或多次,但至少是1次。
1
2
3
4
5
6
7
8
|
[root@node1 ljy] # echo "baat" | gawk '/b[ae]+t/{print $0}' baat [root@node1 ljy] # echo "bt" | gawk '/b[ae]+t/{print $0}' [root@node1 ljy] # echo "bt" | gawk '/ba+t/{print $0}' [root@node1 ljy] # echo "bat" | gawk '/ba+t/{print $0}' bat [root@node1 ljy] # echo "baat" | gawk '/ba+t/{print $0}' baat |
花括号
ERE中的花括号允许你为可重复的正则表达式规定上下限。
m,n最少出现m此,最多出现n次。
1
2
3
|
[root@node1 ljy] # echo "baat" | gawk '/b[ae]{1,2}t/{print $0}' baat [root@node1 ljy] # echo "baaat" | gawk '/b[ae]{1,2}t/{print $0}' |
管道符号
用逻辑or的方式指定正则表达式规则,其中一个条件符合要就即可。
表达式分组
正则表达式分组也可以用圆括号进行分组。
1
2
3
4
5
|
[root@node1 ljy] # echo "bat" | gawk '/b(a|e)t/{print $0}' bat [root@node1 ljy] # echo "baat" | gawk '/b(a|e)t/{print $0}' [root@node1 ljy] # echo "bet" | gawk '/b(a|e)t/{print $0}' bet |
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对脚本之家的支持。
sed
-i
'/^'
$ip
'/d'
/etc/hosts
单引号内是sed的作用域,而ip为shell变量,要使变量ip得到解析,要拿到sed作用域外面来
也可以改为用双引号:sed
-i
"/^$ip/d"
/etc/hosts
[Linux] sed命令使用之在文件中快速删除/增加指定行
1、删除文档的第一行
sed -i '1d' <file>
2、删除文档的最后一行
sed -i '$d' <file>
3、在文档指定行中增加一行
例如文档如下:
echo "1";
echo "2";
echo "4";
echo "5";
想要在echo "2";后面加上一条echo "3";可以用如下命令
sed -i '/echo "2";/aecho "3";' <file>
之所以用分号,是因为文本中本来就有,也就是说分号不是必须的.
抽象出来就是: sed -i '/* /a*' <file>
4、删除文件中的第k行,例如k=3
sed -i '3d' <file>
5、删除文件中包含某个关键字开头的所有行
sed -i '/^QWQ/d' <file>
6、删除文件中包含某个关键字的所有行
sed -i '/QWQ/d' <file>
指定特定的分隔符,查询倒数第二列
awk -F ":" '{print $NF-1}' /etc/passwd
获取第12到31行的第一列的信息
awk -F ":" '{if(NR<31 && NR >12) print $1}' /etc/passwd
Linux_Shell_Shell 中的正则表达式 与 常用正则表达式
在Linux Shell 编程中,我们常需要用到 正则表达式 进行 文件的匹配
在本篇文章中,我们对Linux shell 中的正则表达式 做一个总结,方便之后的shell 编写。
参考文章:
shell编程之正则表达式
https://www.cnblogs.com/whc-uestc/p/4700360.html
shell script 在if 的判断条件正则表达式=~中引号问题
https://www.cnblogs.com/gaochsh/p/6901807.html
shell 正则表达式详细整理
https://www.jb51.net/article/94354.htm
1. 什么是正则表达式
2. 什么是通配符
3. 通配符 与 正则表达式 的区别
4. 基本正则表达式语法
5. 常用的正则表达式
6. 示例,Linux Shell 脚本中正则表达式
===========================================
什么是正则表达式
正则表达式是用于描述字符排列和匹配模式的一种语法规则。
在很多程序设计语言中都支持利用正则表达式来进行字符串的操作,不同语言中的正则表达式略有不同,但是毕竟都是正则,其本质思想都是一致的,当我们掌握了shell中的正则后,再去看python或者perl里面的正则表达式时,会发现其实都是一样的东东。
在shell的一些命令中,有些并不支持正则表达式,但是它们支持Linux里面的通配符,那么通配符又是什么东东呢,它跟正则表达式又有什么关系?我们先来看看 Linux 下的通配符。
===========================================
什么是通配符
通配符是一种特殊语句,主要有星号(*)和问号(?),用来模糊搜索文件。当查找文件夹时,可以使用它来代替一个或多个真正字符;当不知道真正字符或者懒得输入完整名字时,常常使用通配符代替一个或多个真正的字符。
常用正则表达式:
*
代表『 0 个或无穷多个』任意字符
?
代表『一定有一个』任意字符
[ ]
同样代表『一定有一个在括号内』的字符(非任意字符)。例如 [abcd] 代表『一定有一个字符,可能是 a, b, c, d 这四个任何一个』
[ - ]
若有减号在中括号内时,代表『在编码顺序内的所有字符』。例如 [0-9] 代表 0 到 9 之间的所有数字
[^ ]
若中括号内第一个字符为符号 (^) ,那表示『反向选择』,例如 [^abc] 代表 一定有一个字符,要是非 a, b, c 的其他字符就行。
[! ]
若中括号内第一个字符为符号 (!) ,那表示『反向选择』,例如 [!abc] 代表 一定有一个字符,要是非 a, b, c 的其他字符就行。
{String1, String2, ...}
匹配String1 或 String2 (或更多)其一字符串
{c1..c2}
匹配c1-c2 中全部字符,如 {1..2} {a..f} ,只能针对于 同一字符集的组合,
比如 {0a..0f} 会被认为是 {0a..0f} 整体为一个字符串
这种通配符在创建多个文件时比较有用
表:通配符元素优先级规则
优先级 元素 示例1 精确字符 a, \*, \\
2 字符范围 [Aa], [[:digit:]]
3 任意字符 ?
4 重复的精确字符 a+
5 重复的字符范围 [Aa]+, [[:digit:]]+
6 重复的任意字符 ?+
7 任意字符串 *
通配符使用 示例
原始目录
[root@master ~]# ll
总用量 24
-rw-r--r--. 1 root root 4 6月 21 18:09 log_01.error
-rw-r--r--. 1 root root 3 6月 21 18:37 log_02.error
-rw-r--r--. 1 root root 3 6月 21 18:33 log_0.error
-rw-r--r--. 1 root root 3 6月 21 18:34 log_a.error
-rw-------. 1 root root 575 6月 14 21:50 nohup.out
-rw-r--r--. 1 root root 10 4月 17 22:40 test.txt
示例1. 查看log开头的文件
[root@master ~]# ls log*
log_01.error log_02.error log_0.error log_a.error
示例2.查看不是以log开头的文件
先用shopt 开启 extglob模式
[root@master ~]# shopt -s extglob
[root@master ~]# ls !(log*)
nohup.out test.txt
示例3. 查看 log_0?.error 的文件的几种方式
?代表某个数字
[root@master ~]# ll
总用量 24
-rw-r--r--. 1 root root 4 6月 21 18:09 log_01.error
-rw-r--r--. 1 root root 3 6月 21 18:37 log_02.error
-rw-r--r--. 1 root root 3 6月 21 18:33 log_0.error
-rw-r--r--. 1 root root 3 6月 21 18:34 log_a.error
-rw-------. 1 root root 575 6月 14 21:50 nohup.out
-rw-r--r--. 1 root root 10 4月 17 22:40 test.txt
1)ls log_0?.error
[root@master ~]# ls log_0?.error
log_01.error log_02.error
2)ls log_0[0-9].error
[root@master ~]# ls log_0[0-9].error
log_01.error log_02.error
3)ls log_0[[:digit:]].error
[root@master ~]# ls log_0[[:digit:]].error
log_01.error log_02.error
4) ls log_0{0..9}.error
[root@master ~]# ls log_0{0..9}.error
ls: 无法访问log_00.error: 没有那个文件或目录
ls: 无法访问log_03.error: 没有那个文件或目录
ls: 无法访问log_04.error: 没有那个文件或目录
ls: 无法访问log_05.error: 没有那个文件或目录
ls: 无法访问log_06.error: 没有那个文件或目录
ls: 无法访问log_07.error: 没有那个文件或目录
ls: 无法访问log_08.error: 没有那个文件或目录
ls: 无法访问log_09.error: 没有那个文件或目录
log_01.error log_02.error
5) ls log_{01,02}.error
[root@master ~]# ls log_{01,02}.error
log_01.error log_02.error
示例4. 创建多个文件
指令 :
touch 20180622_{0..10}.log
结果 :
[root@master ~]# touch 20180622_{0..10}.log
[root@master ~]# ll总用量 24
-rw-r--r--. 1 root root 0 6月 22 11:36 20180622_0.log
-rw-r--r--. 1 root root 0 6月 22 11:36 20180622_10.log
-rw-r--r--. 1 root root 0 6月 22 11:36 20180622_1.log
-rw-r--r--. 1 root root 0 6月 22 11:36 20180622_2.log
-rw-r--r--. 1 root root 0 6月 22 11:36 20180622_3.log
-rw-r--r--. 1 root root 0 6月 22 11:36 20180622_4.log
-rw-r--r--. 1 root root 0 6月 22 11:36 20180622_5.log
-rw-r--r--. 1 root root 0 6月 22 11:36 20180622_6.log
-rw-r--r--. 1 root root 0 6月 22 11:36 20180622_7.log
-rw-r--r--. 1 root root 0 6月 22 11:36 20180622_8.log
-rw-r--r--. 1 root root 0 6月 22 11:36 20180622_9.log
-rw-r--r--. 1 root root 4 6月 21 18:09 log_01.error
-rw-r--r--. 1 root root 3 6月 21 18:37 log_02.error
-rw-r--r--. 1 root root 3 6月 21 18:33 log_0.error
-rw-r--r--. 1 root root 3 6月 21 18:34 log_a.error
-rw-------. 1 root root 575 6月 14 21:50 nohup.out
-rw-r--r--. 1 root root 10 4月 17 22:40 test.txt
=========================================
通配符 与 正则表达式 的区别
正则表达式用来在文件中匹配符合条件的字符串,正则是包含匹配。
grep、awk、sed等命令都支持正则表达式。
通配符用来匹配符合条件的文件名,通配符是完全匹配。
ls、find、cp这些命令不支持正则表达式,所以只能使用shell自己的通配符来进行匹配了。
首先,正则表达式是用来匹配文件中文本的字符串,而通配符是用来匹配符合条件的文件名;其次正则表达式是包含匹配,只要包含正则中的字符串,就匹配,而通配符是完全匹配,也就是说,必须要与条件中的字符串一模一样才会匹配。
===================================
基本正则表达式语法
正则表达式主要用于字符串的模式分割、匹配、查找及替换操作,下面来关注一下正则表达式基本的元字符和它的作用。
正则表达式的分类
1、基本的正则表达式(Basic Regular Expression 又叫Basic RegEx 简称BREs)
2、扩展的正则表达式(Extended Regular Expression 又叫Extended RegEx 简称EREs)
3、Perl的正则表达式(Perl Regular Expression 又叫Perl RegEx 简称PREs
元字符 | 作用 | 举例说明 |
* | 前一个字符匹配0次或者任意多次 | "a*" 匹配所有内容,包括空白行 "aa*" 匹配至少包含一个a的行 "aaa*" 匹配最后包含两个连续a的字符串 "aaaaa*"匹配最少包含4个连续a的字符串 |
. | 匹配除了换行符外的任意一个字符 |
"s..d" 匹配在s和d这两个字母之间一定有两个 字符的单词 |
^ | 匹配行首 | "^hello" 匹配以hello开头的行 "^M" 匹配以大写“M”开头的行 |
$ | 匹配行尾 | "hello$" 匹配以hello结尾的行 "n$" 匹配以小写“n”结尾的行 "^$" 匹配空白行 |
[] | 匹配中括号中指定的任意一个字符,只匹配一 个字符 |
"[aeiou]" 匹配任意一个元音字母, 两位字符。 "[0-9]" 匹配任意一个数字 "^[a-z]" 匹配小写字母开头的行 |
[^] | 匹配中括号的字符以外的任意一个字符 | "[^0-9]" 匹配任意一位非数字字符, "[^a-z]" 表示任意一位非小写字母 "^[^a-z]" 匹配不是小写字母开头的行 "^[^a-zA-Z]" 匹配不是字母开头的行 |
\ | 转义符。用于将特殊符号的含义取消 | "\.$" 匹配使用"."结尾的行 |
\{n\} | 表示其前面的字符恰好出现n次 | "[0-9]\{4\}" 匹配4位数字, "[1][3-8][0-9]\{9\}" 匹配手机号码 "a\{3\}" 匹配a字母连续出现3次的字符串 "[0-9]\{3\}" 匹配包含连续的3个数字的字符串 |
\{n,\} | 表示其前面的字符出现不小于n次 |
"[0-9]\{2,\}" 表示两位及以上的数字。 的字符串 |
\{n,m\} | 表示其前面的字符至少出现n次,最多出现 m次 |
"[a-z]\{6,8\}" 匹配6到8位的小写字母。 最多三个a |
==============================================
常用的正则表达式
参考文章:
shell 正则表达式详细整理
https://www.jb51.net/article/94354.htm
shell 编程之正则表达式
https://www.cnblogs.com/whc-uestc/p/4700360.html
数字 :
“^\d+$” //非负整数(正整数 + 0)
“^[0-9]*[1-9][0-9]*$” //正整数
“^((-\d+)|(0+))$” //非正整数(负整数 + 0)
“^-[0-9]*[1-9][0-9]*$” //负整数
“^-?\d+$” //整数
“^\d+(\.\d+)?$” //非负浮点数(正浮点数 + 0)
“^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$” //正浮点数
“^((-\d+(\.\d+)?)|(0+(\.0+)?))$” //非正浮点数(负浮点数 + 0)
“^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$” //负浮点数
“^(-?\d+)(\.\d+)?$” //浮点数
字符串:
“^[A-Za-z]+$” //由26个英文字母组成的字符串
“^[A-Z]+$” //由26个英文字母的大写组成的字符串
“^[a-z]+$” //由26个英文字母的小写组成的字符串
“^[A-Za-z0-9]+$” //由数字和26个英文字母组成的字符串
“^\w+$” //由数字、26个英文字母或者下划线组成的字符串
Email :
“^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$” //email地址
“^([w-.]+)@(([[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.)|(([w-]+.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(]?)$” //Email
Url :
“^[a-zA-z]+://(\w+(-\w+)*)(\.(\w+(-\w+)*))*(\?\S*)?$” //url
IP :
“^(d{1,2}|1dd|2[0-4]d|25[0-5]).(d{1,2}|1dd|2[0-4]d|25[0-5]).(d{1,2}|1dd|2[0-4]d|25[0-5]).(d{1,2}|1dd|2[0-4]d|25[0-5])$” //IP地址
Tel :
/^((\+?[0-9]{2,4}\-[0-9]{3,4}\-)|([0-9]{3,4}\-))?([0-9]{7,8})(\-[0-9]+)?$/ //电话号码
日期校验:
/^(d{2}|d{4})-((0([1-9]{1}))|(1[1|2]))-(([0-2]([1-9]{1}))|(3[0|1]))$/ // 年-月-日 yyyy-MM-dd / yy-MM-dd 格式
"^[0-9]{4}-((0([1-9]{1}))|(1[1|2]))-(([0-2]([0-9]{1}))|(3[0|1]))$" // 年-月- 日 yyyy-MM-dd 格式
/^((0([1-9]{1}))|(1[1|2]))/(([0-2]([1-9]{1}))|(3[0|1]))/(d{2}|d{4})$/ // 月/日/年
====================================
Linux Shell 脚本中正则表达式
参考文章:
shell script 在if 的判断条件正则表达式=~中引号问题
https://www.cnblogs.com/gaochsh/p/6901807.html
脚本判断 字符串与某个正则表达式 是否相等
注意:
1) 正则表达式需要写在 =~ 右侧
2) 注意用 [[ ]] 括号
-
-
-
-
date_pattern='^[0-9]{4}-((0([1-9]{1}))|(1[1|2]))-(([0-2]([0-9]{1}))|(3[0|1]))$'
-
-
test_date1='2018-06-22'
-
test_date2='2018-11-40'
-
-
if [[ $test_date1 =~ $date_pattern ]]
-
then
-
echo "date_pattern regex math test_date1 "
-
fi
-
-
if [[ $test_date2 =~ $date_pattern ]]
-
then
-
echo "date_pattern regex math test_date2 "
-
fi
-
-
if [[ $date_pattern =~ $test_date1 ]]
-
then
-
echo "date_pattern regex math test_date2, revert!! "
-
fi
[root@master ~]# sh data_regex.sh
date_pattern regex math test_date1
sed命令用法
sed是一种流编辑器,它是文本处理中非常有用的工具,能够完美的配合正则表达式使用,功能不同凡响。处理时,把当前处理的行存储在临时缓冲区中,称为『模式空间』(pattern space),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。文件内容并没有改变,除非你使用重定向存储输出。sed主要用来自动编辑一个或多个文件,简化对文件的反复操作,编写转换程序等。
1.简介
sed是非交互式的编辑器。它不会修改文件,除非使用shell重定向来保存结果。默认情况下,所有的输出行都被打印到屏幕上。
sed编辑器逐行处理文件(或输入),并将结果发送到屏幕。具体过程如下:首先sed把当前正在处理的行保存在一个临时缓存区中(也称为模式空间),然后处理临时缓冲区中的行,完成后把该行发送到屏幕上。sed每处理完一行就将其从临时缓冲区删除,然后将下一行读入,进行
处理和显示。处理完输入文件的最后一行后,sed便结束运行。sed把每一行都存在临时缓冲区中,对这个副本进行编辑,所以不会修改原文件。
2.定址
定址用于决定对哪些行进行编辑。地址的形式可以是数字、正则表达式、或二者的结合。如果没有指定地址,sed将处理输入文件的所有行。
地址是一个数字,则表示行号;是“$"符号,则表示最后一行。例如:sed -n '$p' /etc/issue
3.命令与选项
sed命令告诉sed如何处理由地址指定的各输入行,如果没有指定地址则处理所有的输入行。
3.1 sed命令
a\
在当前行后添加一行或多行。多行时除最后一行外,每行末尾需用“\”续行 -a,只是显示,如果要真的更改文本,就要sed -i.bak '' 这样就会出来一个带bak格式的文件,这个文件是源文件
[root@entos74 app]#cat -n passwd.txt | sed '10,20a\ 11 adadadadadada '
c\
用此符号后的新文本替换当前行中的文本。多行时除最后一行外,每行末尾需用"\"续行
cat -n passwd.txt | sed '10c\XXXXXXXXXXXXXXXXXX'
i\
在当前行之前插入文本。多行时除最后一行外,每行末尾需用"\"续行
cat -n passwd.txt | sed '10i\XXXXXXXXXXXXXXXXXX'
d
删除行 :ss -ntl |sed '1d' 删除第一行
h
把模式空间里的内容复制到暂存缓冲区
H
把模式空间里的内容追加到暂存缓冲区
g
把暂存缓冲区里的内容复制到模式空间,覆盖原有的内容
G
把暂存缓冲区的内容追加到模式空间里,追加在原有内容的后面
p
打印当前模式空间内容,追加到默认输出之后
n
读入下一输入行,并从下一条命令而不是第一条命令开始对其的处理
q
结束或退出sed
r
从文件中读取输入行
!
对所选行以外的所有行应用命令
s
用一个字符串替换另一个
g
在行内进行全局替换:cat -n passwd.txt | sed 's@/bin/bash$@ /sbin/nologin@g'
w
将所选的行写入文件:sed '/^lixiaozi/w /app/lixiaozi.txt' passwd.txt
x
交换暂存缓冲区与模式空间的内容
y
将字符替换为另一字符(不能对正则表达式使用y命令)
3.2 sed选项
选项
功能
-e
进行多项编辑,即对输入行应用多条sed命令时使用
-n
取消默认的输出
-f
指定sed脚本的文件名
4.退出状态
sed不向grep一样,不管是否找到指定的模式,它的退出状态都是0。只有当命令存在语法错误时,sed的退出状态才不是0。
5.正则表达式元字符
与grep一样,sed也支持特殊元字符,来进行模式查找、替换。不同的是,sed使用的正则表达式是括在斜杠线"/"之间的模式。
如果要把正则表达式分隔符"/"改为另一个字符,比如o,只要在这个字符前加一个反斜线,在字符后跟上正则表达式,再跟上这个字符即可。例如:sed -n '\o^Myop' datafile
元字符
功能
示例
^
行首定位符
/^my/ 匹配所有以my开头的行
$
行尾定位符
/my$/ 匹配所有以my结尾的行
.
匹配除换行符以外的单个字符
/m..y/ 匹配包含字母m,后跟两个任意字符,再跟字母y的行
*
匹配零个或多个前导字符
/my*/ 匹配包含字母m,后跟零个或多个y字母的行
[]
匹配指定字符组内的任一字符
/[Mm]y/ 匹配包含My或my的行
[^]
匹配不在指定字符组内的任一字符
/[^Mm]y/ 匹配包含y,但y之前的那个字符不是M或m的行
\(..\)
保存已匹配的字符
1,20s/\(you\)self/\1r/ 标记元字符之间的模式,并将其保存为标签1,之后可以使用\1来引用它。最多可以定义9个标签,从左边开始编号,最左边的是第一个。此例中,对第1到第20行进行处理,you被保存为标签1,如果发现youself,则替换为your。
&
保存查找串以便在替换串中引用
s/my/**&**/ 符号&代表查找串。my将被替换为**my**
\<
词首定位符
/\<my/ 匹配包含以my开头的单词的行
\>
词尾定位符
/my\>/ 匹配包含以my结尾的单词的行
x\{m\}
连续m个x
/9\{5\}/ 匹配包含连续5个9的行
x\{m,\}
至少m个x
/9\{5,\}/ 匹配包含至少连续5个9的行
x\{m,n\}
至少m个,但不超过n个x
/9\{5,7\}/ 匹配包含连续5到7个9的行
6.范例
6.1 p命令
命令p用于显示模式空间的内容。默认情况下,sed把输入行打印在屏幕上,选项-n用于取消默认的打印操作。当选项-n和命令p同时出现时,sed可打印选定的内容。
sed '/my/p' datafile
#默认情况下,sed把所有输入行都打印在标准输出上。如果某行匹配模式my,p命令将把该行另外打印一遍。
[root@entos74 ~]#sed -n '3p' filelist.txt
只打印第三行
只显示指定行范围的文件内容,例如:
# 只查看文件的第20行到第30行,并且带上行号
cat -n /etc/passwd | sed -n '20,30p'
6.2 d命令
命令d用于删除输入行。sed先将输入行从文件复制到模式空间里,然后对该行执行sed命令,最后将模式空间里的内容显示在屏幕上。如果发出的是命令d,当前模式空间里的输入行会被删除,不被显示。
sed '$d' datafile
#删除最后一行,其余的都被显示
cat -n passwd.txt | sed '/mail/,25d'
#删除包含"mail"的行到第25行的内容
地址是逗号分隔的,那么需要处理的地址是这两行之间的范围(包括这两行在内)。范围可以用数字、正则表达式、或二者的组合表示。例如:
sed '2,5d' datafile
#删除第二到第五行
sed '/My/,/You/d' datafile
#删除包含"My"的行到包含"You"的行之间的行
6.3 s命令
sed 's/^My/You/g' datafile
#命令末端的g表示在行内进行全局替换,也就是说如果某行出现多个My,所有的My都被替换为You。
6.4 e选项
-e是编辑命令,用于sed执行多个编辑任务的情况下。在下一行开始编辑前,所有的编辑动作将应用到模式缓冲区中的行上。
sed -e '1,10d' -e 's/My/Your/g' datafile
#选项-e用于进行多重编辑。第一重编辑删除第1-3行。第二重编辑将出现的所有My替换为Your。因为是逐行进行这两项编辑(即这两个命令都在模式空间的当前行上执行),所以编辑命令的顺序会影响结果。
6.5 w命令
sed -n '/hrwang/w me.txt' datafile
6.6 a\ 命令
a\ 命令是追加命令,追加将添加新文本到文件中当前行(即读入模式缓冲区中的行)的后面。所追加的文本行位于sed命令的下方另起一行。如果要追加的内容超过一行,则每一行都必须以反斜线结束,最后一行除外。最后一行将以引号和文件名结束。
sed '/^hrwang/a\
>hrwang and mjfan are husband\
>and wife' datafile
#如果在datafile文件中发现匹配以hrwang开头的行,则在该行下面追加hrwang and mjfan are husband and wife
6.7 i\ 命令
i\ 命令是在当前行的前面插入新的文本。
6.8 c\ 命令
sed使用该命令将已有文本修改成新的文本。
6.9 n命令
sed使用该命令获取输入文件的下一行,并将其读入到模式缓冲区中,任何sed命令都将应用到匹配行紧接着的下一行上。
sed '/hrwang/{n;s/My/Your/;}' datafile
总结
awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。
使用方法 : awk '{pattern + action}' {filenames}
尽管操作可能会很复杂,但语法总是这样,其中 pattern 表示 AWK 在数据中查找的内容,而 action 是在找到匹配内容时所执行的一系列命令。花括号({})不需要在程序中始终出现,但它们用于根据特定的模式对一系列指令进行分组。 pattern就是要表示的正则表达式,用斜杠括起来。
awk语言的最基本功能是在文件或者字符串中基于指定规则浏览和抽取信息,awk抽取信息后,才能进行其他文本操作。完整的awk脚本通常用来格式化文本文件中的信息。通常,awk是以文件的一行为处理单位的。awk每接收文件的一行,然后执行相应的命令,来处理文本。
awk内置变量
1
2
3
4
5
6
7
8
9
10
11
12
|
ARGC 命令行参数个数 ARGV 命令行参数排列 ENVIRON 支持队列中系统环境变量的使用 FILENAME awk 浏览的文件名 FNR 浏览文件的记录数 FS 设置输入域分隔符,等价于命令行 -F选项 NF 浏览记录的域的个数 NR 已读的记录数 OFS 输出域分隔符 ORS 输出记录分隔符 RS 控制记录分隔符 $0变量是指整条记录。$1表示当前行的第一个域,$2表示当前行的第二个域,......以此类推。 |
1
|
$NF是number finally,表示最后一列的信息,跟变量NF是有区别的,变量NF统计的是每行列的总数 |
常用的命令展示
awk擅长列输出
搜索/etc/passwd有root关键字的所有行
1
|
awk '/root/' /etc/passwd 【这种是pattern的使用,匹配了pattern(这里是root)的行才会执行action(没有指定action,默认输出每行的内容)】 |
搜索/etc/passwd有root关键字的所有行,并显示对应的shell
1
|
awk -F: '/root/ {print $7}' /etc/passwd |
统计/etc/passwd:文件名,每行的行号,每行的列数,对应的完整行内容:
1
|
awk -F ':' '{print "filename:" FILENAME ",linenumber:" NR ",columns:" NF ",linecontent:"$0}' /etc/passwd |
使用printf替代print,可以让代码更加简洁,易读
1
|
awk -F: '{printf ("filename:%10s, linenumber:%3s,column:%3s,content:%3f\n",FILENAME,NR,NF,$0)}' /etc/passwd |
打印/etc/passwd/的第二行信息
1
|
awk -F: 'NR==2{print "filename: "FILENAME, $0}' /etc/passwd |
awk的过滤使用方法
1
|
ls -lF | awk '/^d/' |
1
|
awk -F ":" '{print $1}' /etc/passwd |
1
|
awk -F ":" '{print $NF}' /etc/passwd |
1
|
awk -F ":" '{print $NF-1}' /etc/passwd |
1
|
awk -F ":" '{if(NR<31 && NR >12) print $1}' /etc/passwd |
多分隔符的使用:
1
2
|
[root@localhost ftl] # awk -F "[/]" 'NR == 4 {print $0,"\n",$1}' /etc/passwd 这里以/为分隔符,多个分隔符利用[]然后在里面写分隔符即可 |
1
|
[root@localhost ftl] # cat /etc/passwd | awk -F: 'BEGIN{print "name, shell"} {print $1,$NF} END{print "hello world"}' |
查看最近登录最多的IP信息
1
|
[root@localhost ftl] # last | awk '{S[$3]++} END{for(a in S ) {print S[a],a}}' |uniq| sort -rh |
利用正则过滤多个空格
1
|
[root@localhost ~] # ifconfig |grep eth* | awk -F '[ ]+' '{print $1}'<br><br> |
awk编程--变量和赋值
除了awk的内置变量,awk还可以自定义变量, awk中的循环语句同样借鉴于C语言,支持while、do/while、for、break、continue,这些关键字的语义和C语言中的语义完全相同。
统计某个文件夹下的大于100k文件的数量和总和
1
2
|
ls -l| awk '{if($5>100){count++; sum+=$5}} {print "Count:" count,"Sum: " sum}' 【因为 awk 会轮询统计,所以会显示整个过程】 ls -l| awk '{if($5>100){count++; sum+=$5}} END{print "Count:" count,"Sum: " sum}' 【天界END后只显示最后的结果】 |
1
|
<strong>备注:< /strong >count是自定义变量。之前的action{}里都是只有一个print,其实print只是一个语句,而action{}可以有多个语句,以;号隔开 |
统计显示/etc/passwd的账户
1
2
3
|
awk -F: '{count++;} END{print count}' /etc/passwd cat /etc/passwd | wc -l awk -F ':' 'BEGIN {count=0;} {name[count] = $1;count++;}; END{for (i = 0; i < NR; i++) print i, name[i]}' /etc/passwd |
Linux xargs命令详解
find命令把匹配到的文件传递给xargs命令,而xargs命令每次只获取一部分文件而不是全部
xargs要处理的文件如果不是在结尾,需要加上 -i这个参数
xargs常见命令参数
args:xargs的默认命令是echo,空格是默认定界符。 默认替换符号是{}
1
2
3
4
|
-I {}批定了替换字符串,表示文件内容,能循环按要求替换相应的参数 使用-I指定一个替换字符串{},这个字符串在 xargs 扩展时会被替换掉, 当-I与 xargs 结合使用,每一个参数命令都会被执行一次: -n num 后面加次数,表示命令在执行的时候一次用的argument的个数,默认是用所有的 -d 自定义定界符 |
常用的命令展示
多行内容的单输出且每行3个
1
|
[root@localhost ftl] # cat /home/omc/ftl/logs.txt |xargs -n3 |
查找系统中的每一个普通文件,然后使用xargs命令来测试它们分别属于哪类文件
1
|
[root@localhost log] # find /home/omc/ -maxdepth 1 -user root -type f | xargs file {} |
在/var/log/下查找log文件,复制文件到/home/omc/ftl且把结果保存到/home/omc/ftl/logs.txt文件中
1
2
3
4
|
[root@localhost log] # find /var/log/*.log -type f | xargs -i cp {} /home/omc/ftl [root@localhost log] # ll -ltr /home/omc/ftl [root@localhost log] # find /var/log/*.log -type f > /home/omc/ftl/logs.txt [root@localhost log] # ll /home/omc/ftl/logs.txt |
删除 /home/omc/ftl/下的log文件
1
2
|
[root@localhost ftl] # ll *.log |xargs rm -rf {} 【错误】 [root@localhost ftl] # ls *.log |xargs rm -rf {} 【正确】 |
在当前目录下查找所有用户权限644的文件,并更改权限600
1
2
3
|
[root@localhost ftl] # ll *.txt [root@localhost ftl] # find /home/omc/ftl -perm 644 | xargs chmod 600 [root@localhost ftl] # ll *.txt |
用grep命令在当前目录下的所有普通文件中搜索omc这个词
1
2
|
find /etc/ -name \* - type f | xargs grep "omc" > /tmp/ftl ==> find /etc/ -name "*" - type f | xargs grep "omc" > /tmp/ftl |
使用-i参数默认的前面输出用{}代替,-I参数可以指定其他代替字符,如例子中的[]
find /var/ -name "*.log" |xargs -I [] cp [] /tmp/ 【xargs 默认用是i表示{},用I可以替换符号】
ll -ltr /tmp/ | more 5
xargs的-p参数的使用
find . -name "*.log" |xargs -p -i cp {} ../ltesig/
【-p参数会提示让你确认是否执行后面的命令,y执行,n不执行】
利用for循环实现和xargs同样的效果
1
2
|
find /home/omc/ -name *.txt | xargs -i cp {} /home/omc/h cat logs.txt | while read line; do echo $line >> logs_bak.txt; done ; |
利用xargs关闭不常用的系统启动软件
1
|
chkconfig | awk '{print $1}' | grep -Ev "sshd|network|crond|sysstat|rsyslog" | xargs -I{} chkconfig {} off |
xargs总结示范:
1
2
3
4
5
|
find . -name "*.log" | xargs -p -i cp {} .. /ltesig/ 【正确】 find . -name "*.log" | xargs -p cp {} .. /ltesig/ 【错误】 find . - type f -print | xargs file 【正确】 find . - type f -print | xargs rm {} 【错误】 总结一下:如果命令后面可以跟内容,且没有目的路径的时候,可以省略-i,否则得加上 |
怎么通过进程找到程序
通过进程找到pid号码
[root@clsn proc]# ps -ef |grep sshd root 1294 1 0 09:18 ? 00:00:00 /usr/sbin/sshd -D
通过pid找到在proc目录下的临时文件夹
[root@clsn proc]# cd /proc/1294 [root@clsn 1294]#
查看其中的exe文件,即可发现程序文件的路径
[root@clsn 1294]# ll exe lrwxrwxrwx 1 root root 0 12月 11 09:18 exe -> /usr/sbin/sshd
脚本调试技巧
调试技巧1:使用dos2unix处理脚本
从windows编辑的脚本到Linux下需要使用这个命令 dos2unix windows.sh
调试技巧2:使用echo命令调试
在变量读取或修改的前后加入echo $变量,也可在后面使用exit退出脚本,这样可以不用注释后面的代码
调试技巧3:sh -x 脚本 ==》全局调试
sh -x scripts.sh
调试技巧4:局部调试
set -x 要调试的脚本内容 set +x
不退出vim执行
::!bash change_ip.sh 10.190.172.6 10.190.172.7
VIM中执行Shell命令,有以下几种形式:
1. :!command
不退出vim,并执行shell命令command,将命令输出显示在vim的命令区域,不会改变当前编辑的文件的内容 例如::!ls -l,如果你正在编辑一个脚本,vim ErrorMail.sh,代码基本写完,你想测试一下你不用保存退出,你可以先保存 :w! 然后再执行这个脚本 :!sh ErrorMai.sh.此时你并没有退出vim编辑器,返回结果后,你只要回车一下可以继续编辑
2. :r!command
将shell命令command的结果插入到当前行的下一行.例如::r!date,读取系统时间并插入到当前行的下一行。
3. :起始行号,结束行号 !command
将起始行号和结束行号指定的范围中的内容输入到shell命令command处理,并将处理结果替换起始行号和结束行号指定的范围中的内容.例如:62,72 !sort,将62行到72行的内容进行排序,可以只指定起始行,例如:62 !tr [a-z] [A-Z],将62行的小写字母转为大写字母
linux shell 脚本输入参数解析
#!/bin/bash
para="para: ";
while [ $# -ge 2 ] ; do
case "$1" in
--aa) para="${para} argument $1 = $2;"; shift 2;;
--bb) para="${para} argument $1 = $2;"; shift 2;;
*) echo "unknown parameter $1." ; exit 1 ; break;;
esac
done
echo $para
./test.sh --aa 123 --bb 456
Linux shell 变量的基本运算
数值作为常规变量直接赋值给变量,并且以字符串形式保存。
let 命令可以用于直接执行基本操作:
当我使用 let 的时候,我们不使用 $ 符号引用变量。
no1=7;
no2=8;
echo "------------ let command -------------"
let no1++;
let no2--;
let no1+=3;
let no2-=5;
let result=no1+no2;
printf "let result=%d\n" $result;
" [ ] "运算符跟 let 命令很相似:
"[ ]" 运算符里面可以使用 $ 符号引用变量,同时支持变量名与运算符之间不带空格。
echo "----------------- [] operator ----------------"
printf "no1:%d no2:%d \n" $no1 $no2;
result1=$[ no1 + no2 ];
printf "result1 = %d \n" $result1;
result2=$[no1+no2 + 7];
printf "result2 = %d \n" $result2;
result3=$[ $no1+$no2+5 ];
printf "result3 = %d \n" $result3;
no2=$[ no2 + 1 ];
printf "no1 = %d no2 = %d \n" $no1 $no2;
" (( )) " 运算符跟 " [ ] " 运算符一样:
同样支持使用 $ 符号引用变量进行基本运算,同时支持变量名与运算符之间不带空格。
echo "----------------- (( )) operator --------------"
printf "no1: %d no2: %d \n" $no1 $no2;
result1=$(( no1 + no2 ));
printf "result1 = %d \n" $result1;
result2=$((no1+no2+3));
printf "result2 = %d \n" $result2;
result3=$(( $no1+$no2 + 5))
printf "result3 = %d \n" $result3;
"expr" 命令同样可以用于变量的基本运算:
"expr" 命令同样支持 $ 符号引用变量进行基本运算,但是变量与运算符之间必须使用空格作为分隔符;
在使用 "expr" 命令对变量进行运算后,整个表达式必须使用 " · expression · " 的模式赋值给变量,即包含在 " ` " 符里面,
并且等效于 " $( expression ) " 模式。
echo "---------------- expr command ---------------"
printf "no1: %d no2: %d \n" $no1 $no2;
result1=`expr 3 + 4`;
printf "result1 = %d \n" $result1;
result2=`expr $no1 + 4`;
printf "result2 = %d \n" $result2;
result3=`expr $no1 + $no2`;
printf "result3 = %d \n" $result3;
result4=`expr $no1+$no2`;
printf "result4 = %d \n" $result4;
result5=$(expr $no1 + 3);
printf "result5 = %d \n" $result5;
result6=$(expr $no1+4);
printf "result6 = %d \n" $result6;
result7=$(expr $no1+$no2);
printf "result7 = %d \n" $result7;
" expr " 命令的表达式中,变量与运算符之间必须使用空格作为分隔符,
上面所述的四种shell中执行变量运算的方式中不支持浮点运算!
2, Linux shell 中使用 bc 命令实现高级数学运算:
bc有三个参数,scale是运算精度,ibase指定输入变量的记数进制;obase指定输出变量的记数进制;
bc 命令使用 标准输入 stdin 作为输入;
bc 是一个支持精确的浮点运算的高级计算器;
bc 拥有相当多的输入选项,并且支持数学函数调用;
执行 bc --help 自行查看 bc 所支持的输入选项;
2.1 bc 命令使用标准输入 stdin 作为输入,并且支持浮点运算:
echo "----------------- bc command ----------------"
echo "4 * 0.56" | bc;
no=48;
result1=`echo "$no * 1.5" | bc`;
echo "result1 = $result1";
2.2 bc 命令支持运算精度设置:
通过附加参数可以给 bc 指定运算精度;指定输入变量的记数进制;
附加参数使用分号 " ; " 作为分隔符;
result2=`echo "scale=9;$no / 3;" | bc`;
echo "result2 = $result2";
实验结果所示,使用分号 " ; " 加入附加参数 scale ,指定精度为 9 位小数;
2.3 使用 bc 进行数值的记数进制间转换:
通过 ibase=value 作为附加参数,指定输入变量的记数进制;
通过 obase=value 作为附加参数,指定输出变量的记数进制;
no=100;
echo "echo \"obase=2;ibase=10;$no\" | bc = `echo "obase=2;ibase=10;$no" | bc`";
no=1000;
echo "echo \"scale=5;obase=10;ibase=2;$no/3\" | bc = `echo "scale=5;obase=10;ibase=2;$no/3" | bc`";
2.4 使用 bc 调用数学公式进行高级数学运算:
" sqrt(value) " 执行 value 的开方运算;
" value^index " 执行 value 的幂运算;
echo "sqrt(100) = `echo "sqrt(100)" | bc`";
echo "sqrt(100) = $(echo "sqrt(100)" | bc)";
echo "10^3 = `echo "10^3" | bc`";
echo "10^3 = $(echo "10^3" | bc)";
Linux之awk内建数学函数之左移运算、右移运算、按位取反运算
位操作是程序设计中对位模式按位或二进制数的一元和二元操作。在许多古老的微处理器上,位运算比加减运算略快,通常位运算比乘除法运算要快很多。在现代架构中,情况并非如此:位运算的运算速度通常与加法运算相同(仍然快于乘法运算)。移位是一个二元运算符,用来将一个二进制数中的每一位全部都向一个方向移动指定位,溢出的部分将被舍弃,而空缺的部分填入一定的值。
程序设计中,位操作运算符的一种。在c++中,移位运算符有双目移位运算符:<<(左移)和>>(右移)。移位运算符组成的表达式也属于算术表达式,其值为算术值。左移运算是将一个二进制位的操作数按指定移动的位数向左移位,移出位被丢弃,右边的空位一律补0。右移运算是将一个二进制位的操作数按指定移动的位数向右移动,移出位被丢弃,左边移出的空位或者一律补0,或者补符号位,这由不同的机器而定。在使用补码作为机器数的机器中,正数的符号位为0,负数的符号位为1。
在移位运算时,byte、short和char类型移位后的结果会变成int类型,对于byte、short、char和int进行移位时,规定实际移动 的次数是移动次数和32的余数,也就是移位33次和移位1次得到的结果相同。移动long型的数值时,规定实际移动的次数是移动次数和64的余数,也就是 移动66次和移动2次得到的结果相同。
[root@Legion10 ~]# echo 233 | awk '{print lshift($1,5),rshift($1,5),$1}'
7456 7 233
[root@Legion10 ~]#
解析:
[root@Legion10 ~]# echo 233 | awk '{print lshift($1,5),rshift($1,5),$1}'
7456 7 233
[root@Legion10 ~]# cat 2
dec bin | dec bin
233 0000011101001 | 233 11101001
7456 1110100100000 | 7 00000111
----左移5位------------- | ----右移5位------------
[root@Legion10 ~]#
Linux之awk内建数学函数之左移运算、右移运算、按位取反运算
来个右移位运算计算ip
[root@Legion10 ~]# echo 134744072|awk '{
a=0xFF000000;
b=0xFF0000;
c=0xFF00;
d=0xFF;
e=rshift(and($1,a),24);
f=rshift(and($1,b),16);
g=rshift(and($1,c),8);
h=and($1,d);
printf("%d.%d.%d.%d\n",e,f,g,h)
}'
8.8.8.8
[root@Legion10 ~]#
Linux之awk内建数学函数之左移运算、右移运算、按位取反运算
bash脚本中没有移位运算符。不过可以借助awk脚本来实现。
比如对数字 N 右移3位
echo N | awk '{print rshift($0, 3)} '
又如,左移5位
echo N | awk '{print lshift($0, 5)} '
各种括号的作用()、(())、[]、[[]]、{}
小括号,圆括号()
单小括号 ()
①命令组。括号中的命令将会新开一个子shell顺序执行,所以括号中的变量不能够被脚本余下的部分使用。括号中多个命令之间用分号隔开,最后一个命令可以没有分号,各命令和括号之间不必有空格。
②命令替换。等同于`cmd`,shell扫描一遍命令行,发现了$(cmd)结构,便将$(cmd)中的cmd执行一次,得到其标准输出,再将此输出放到原来命令。有些shell不支持,如tcsh。
③用于初始化数组。如:array=(a b c d)
双小括号 (( ))
①整数扩展。这种扩展计算是整数型的计算,不支持浮点型。((exp))结构扩展并计算一个算术表达式的值,如果表达式的结果为0,那么返回的退出状态码为1,或者 是"假",而一个非零值的表达式所返回的退出状态码将为0,或者是"true"。若是逻辑判断,表达式exp为真则为1,假则为0。
②只要括号中的运算符、表达式符合C语言运算规则,都可用在$((exp))中,甚至是三目运算符。作不同进位(如二进制、八进制、十六进制)运算时,输出结果全都自动转化成了十进制。如:echo $((16#5f)) 结果为95 (16进位转十进制)
③单纯用 (( )) 也可重定义变量值,比如 a=5; ((a++)) 可将 $a 重定义为6
④常用于算术运算比较,双括号中的变量可以不使用$符号前缀。括号内支持多个表达式用逗号分开。 只要括号中的表达式符合C语言运算规则,比如可以直接使用for((i=0;i<5;i++)), 如果不使用双括号, 则为for i in `seq 0 4`或者for i in {0..4}。再如可以直接使用if (($i<5)), 如果不使用双括号, 则为if [ $i -lt 5 ]。
中括号,方括号[]
单中括号 []
①bash 的内部命令,[和test是等同的。如果我们不用绝对路径指明,通常我们用的都是bash自带的命令。if/test结构中的左中括号是调用test的命令标识,右中括号是关闭条件判断的。这个命令把它的参数作为比较表达式或者作为文件测试,并且根据比较的结果来返回一个退出状态码。if/test结构中并不是必须右中括号,但是新版的Bash中要求必须这样。
②Test和[]中可用的比较运算符只有==和!=,两者都是用于字符串比较的,不可用于整数比较,整数比较只能使用-eq,-gt这种形式。无论是字符串比较还是整数比较都不支持大于号小于号。如果实在想用,对于字符串比较可以使用转义形式,如果比较"ab"和"bc":[ ab \< bc ],结果为真,也就是返回状态为0。[ ]中的逻辑与和逻辑或使用-a 和-o 表示。
③字符范围。用作正则表达式的一部分,描述一个匹配的字符范围。作为test用途的中括号内不能使用正则。
④在一个array 结构的上下文中,中括号用来引用数组中每个元素的编号。
双中括号[[ ]]
①[[是 bash 程序语言的关键字。并不是一个命令,[[ ]] 结构比[ ]结构更加通用。在[[和]]之间所有的字符都不会发生文件名扩展或者单词分割,但是会发生参数扩展和命令替换。
②支持字符串的模式匹配,使用=~操作符时甚至支持shell的正则表达式。字符串比较时可以把右边的作为一个模式,而不仅仅是一个字符串,比如[[ hello == hell? ]],结果为真。[[ ]] 中匹配字符串或通配符,不需要引号。
③使用[[ ... ]]条件判断结构,而不是[ ... ],能够防止脚本中的许多逻辑错误。比如,&&、||、<和> 操作符能够正常存在于[[ ]]条件判断结构中,但是如果出现在[ ]结构中的话,会报错。比如可以直接使用if [[ $a != 1 && $a != 2 ]], 如果不适用双括号, 则为if [ $a -ne 1] && [ $a != 2 ]或者if [ $a -ne 1 -a $a != 2 ]。
④bash把双中括号中的表达式看作一个单独的元素,并返回一个退出状态码。
例子:
if ($i<5)
if [ $i -lt 5 ]
if [ $a -ne 1 -a $a != 2 ]
if [ $a -ne 1] && [ $a != 2 ]
if [[ $a != 1 && $a != 2 ]]
for i in $(seq 0 4);do echo $i;done
for i in `seq 0 4`;do echo $i;done
for ((i=0;i<5;i++));do echo $i;done
for i in {0..4};do echo $i;done
大括号、花括号 {}
常规用法
①大括号拓展。(通配(globbing))将对大括号中的文件名做扩展。在大括号中,不允许有空白,除非这个空白被引用或转义。第一种:对大括号中的以逗号分割的文件列表进行拓展。如 touch {a,b}.txt 结果为a.txt b.txt。第二种:对大括号中以点点(..)分割的顺序文件列表起拓展作用,如:touch {a..d}.txt 结果为a.txt b.txt c.txt d.txt
# ls {ex1,ex2}.sh
ex1.sh ex2.sh
# ls {ex{1..3},ex4}.sh
ex1.sh ex2.sh ex3.sh ex4.sh
# ls {ex[1-3],ex4}.sh
ex1.sh ex2.sh ex3.sh ex4.sh
②代码块,又被称为内部组,这个结构事实上创建了一个匿名函数 。与小括号中的命令不同,大括号内的命令不会新开一个子shell运行,即脚本余下部分仍可使用括号内变量。括号内的命令间用分号隔开,最后一个也必须有分号。{}的第一个命令和左括号之间必须要有一个空格。
几种特殊的替换结构
${var:-string},${var:+string},${var:=string},${var:?string}
①${var:-string}和${var:=string}:若变量var为空,则用在命令行中用string来替换${var:-string},否则变量var不为空时,则用变量var的值来替换${var:-string};对于${var:=string}的替换规则和${var:-string}是一样的,所不同之处是${var:=string}若var为空时,用string替换${var:=string}的同时,把string赋给变量var: ${var:=string}很常用的一种用法是,判断某个变量是否赋值,没有的话则给它赋上一个默认值。
② ${var:+string}的替换规则和上面的相反,即只有当var不是空的时候才替换成string,若var为空时则不替换或者说是替换成变量 var的值,即空值。(因为变量var此时为空,所以这两种说法是等价的)
③${var:?string}替换规则为:若变量var不为空,则用变量var的值来替换${var:?string};若变量var为空,则把string输出到标准错误中,并从脚本中退出。我们可利用此特性来检查是否设置了变量的值。
补充扩展:在上面这五种替换结构中string不一定是常值的,可用另外一个变量的值或是一种命令的输出。
四种模式匹配替换结构
模式匹配记忆方法:
# 是去掉左边(在键盘上#在$之左边)
% 是去掉右边(在键盘上%在$之右边)
#和%中的单一符号是最小匹配,两个相同符号是最大匹配。
${var%pattern},${var%%pattern},${var#pattern},${var##pattern}
第一种模式:${variable%pattern},这种模式时,shell在variable中查找,看它是否一给的模式pattern结尾,如果是,就从命令行把variable中的内容去掉右边最短的匹配模式
第二种模式: ${variable%%pattern},这种模式时,shell在variable中查找,看它是否一给的模式pattern结尾,如果是,就从命令行把variable中的内容去掉右边最长的匹配模式
第三种模式:${variable#pattern} 这种模式时,shell在variable中查找,看它是否一给的模式pattern开始,如果是,就从命令行把variable中的内容去掉左边最短的匹配模式
第四种模式: ${variable##pattern} 这种模式时,shell在variable中查找,看它是否一给的模式pattern结尾,如果是,就从命令行把variable中的内容去掉右边最长的匹配模式
这四种模式中都不会改变variable的值,其中,只有在pattern中使用了*匹配符号时,%和%%,#和##才有区别。结构中的pattern支持通配符,*表示零个或多个任意字符,?表示仅与一个任意字符匹配,[...]表示匹配中括号里面的字符,[!...]表示不匹配中括号里面的字符。
# var=testcase
# echo $var
testcase
# echo ${var%s*e}
testca
# echo $var
testcase
# echo ${var%%s*e}
te
# echo ${var#?e}
stcase
# echo ${var##?e}
stcase
# echo ${var##*e}
# echo ${var##*s}
e
# echo ${var##test}
case
字符串提取和替换
${var:num},${var:num1:num2},${var/pattern/pattern},${var//pattern/pattern}
第一种模式:${var:num},这种模式时,shell在var中提取第num个字符到末尾的所有字符。若num为正数,从左边0处开始;若num为负数,从右边开始提取字串,但必须使用在冒号后面加空格或一个数字或整个num加上括号,如${var: -2}、${var:1-3}或${var:(-2)}。
第二种模式:${var:num1:num2},num1是位置,num2是长度。表示从$var字符串的第$num1个位置开始提取长度为$num2的子串。不能为负数。
第三种模式:${var/pattern/pattern}表示将var字符串的第一个匹配的pattern替换为另一个pattern。。
第四种模式:${var//pattern/pattern}表示将var字符串中的所有能匹配的pattern替换为另一个pattern。
[root@centos ~]# var=/home/centos
[root@centos ~]# echo $var
/home/centos
[root@centos ~]# echo ${var:5}
/centos
[root@centos ~]# echo ${var: -6}
centos
[root@centos ~]# echo ${var:(-6)}
centos
[root@centos ~]# echo ${var:1:4}
home
[root@centos ~]# echo ${var/o/h}
/hhme/centos
[root@centos ~]# echo ${var//o/h}
/hhme/cenths
符号$后的括号
(1)${a} 变量a的值, 在不引起歧义的情况下可以省略大括号。
(2)$(cmd) 命令替换,和`cmd`效果相同,结果为shell命令cmd的输,过某些Shell版本不支持$()形式的命令替换, 如tcsh。
(3)$((expression)) 和`exprexpression`效果相同, 计算数学表达式exp的数值, 其中exp只要符合C语言的运算规则即可, 甚至三目运算符和逻辑表达式都可以计算。
使用
1、多条命令执行
(1)单小括号,(cmd1;cmd2;cmd3) 新开一个子shell顺序执行命令cmd1,cmd2,cmd3, 各命令之间用分号隔开, 最后一个命令后可以没有分号。
(2)单大括号,{ cmd1;cmd2;cmd3;} 在当前shell顺序执行命令cmd1,cmd2,cmd3, 各命令之间用分号隔开, 最后一个命令后必须有分号, 第一条命令和左括号之间必须用空格隔开。
对{}和()而言, 括号中的重定向符只影响该条命令, 而括号外的重定向符影响到括号中的所有命令。
解决Linux系统中出现You have new mail in /var/spool/mail/root的问题
第一步
关闭提示
echo "unset MAILCHECK">> /etc/profile
source /etc/profile
第二步
查看
ls -lth /var/spool/mail/
清空
cat /dev/null > /var/spool/mail/root
2>&1表示,我把错误输出重定向到标准屏幕输出1上,在赋值给变量aa
echo "errormsg" >&2; 标准错误
echo "infomsg" >&1; 标准输出
cat一个不存在的文件,会有错误输出,我可以把错误重定向到文件里
用管道符'>'重定向标准错误输出:
#cat /tmp/aa
cat: /tmp/aa: No such file or directory
#cat /tmp/aa 2>err.log
#cat err.log
cat: /tmp/aa: No such file or directory
Shell中 &>/dev/null和 >/dev/null 2>&1
将脚本的主体包装在大括号中并重定向到/ dev / null:
#!/usr/bin/ksh
{
for i in *.DAT
do
awk 'BEGIN{OFS=FS=","}$3~/^353/{$3="353861958962"}{print}' $i >> $i_changed
awk '$3~/^353/' $i_changed >> $i_353
rm -rf $i_changed
done
} >/dev/null 2>&1
这也会将错误发送到比特桶.这可能不是一个好主意;如果您不想这样,请删除2>& 1重定向.
另外:注意 – 您可能需要使用${i} _changed和${i} _353.这就是为什么输出不会转到文件…你的变量${i_changed}和${i_353}没有初始化,因此重定向不命名文件.
文件描述符
文件描述符是与文件输入、输出关联的整数。它们用来跟踪已打开的文件。最常见的文件描述符是stidin、stdout、和stderr。我们可以将某个文件描述符的内容重定向到另外一个文件描述符中。
文件描述符我们常见的就是系统预留的0,1和2这三个,他们的意义分别有如下对应关系:
0 —— stdin(标准输入)
1 —— stdout (标准输出)
2 —— stderr (标准错误)
关于如何调试shell脚本
#sh -vx xxxx.sh
echo命令
|
|
echo命令用于在shell中打印shell变量的值,或者直接输出指定的字符串。linux的echo命令,在shell编程中极为常用, 在终端下打印变量value的时候也是常常用到的,因此有必要了解下echo的用法echo命令的功能是在显示器上显示一段文字,一般起到一个提示的作 用。
语法
echo(选项)(参数)选项
-e:激活转义字符。使用-e选项时,若字符串中出现以下字符,则特别加以处理,而不会将它当成一般文字输出:
?\a 发出警告声;
?\b 删除前一个字符;
?\c 最后不加上换行符号;
?\f 换行但光标仍旧停留在原来的位置;
?\n 换行且光标移至行首;
?\r 光标移至行首,但不换行;
?\t 插入tab;
?\v 与\f相同;
?\ 插入\字符;
?\nnn 插入nnn(八进制)所代表的ASCII字符;
用echo命令打印带有色彩的文字:
其中“F“为字体颜色,编号为30-37,“B”为背景颜色,编号为40-47。颜色表如下
F B
30 40 黑色
31 41 红色
32 42 绿色
33 43 黄色
34 44 蓝色
35 45 紫红色
36 46 青蓝色
37 47 白色
文字色:
echo -e "\e[1;31mThis is red text\e[0m"
This is red text?\e[1;31m 将颜色设置为红色
?\e[0m 将颜色重新置回
颜色码:重置=0,黑色=30,红色=31,绿色=32,黄色=33,蓝色=34,洋红=35,青色=36,白色=37
背景色:
echo -e "\e[1;42mGreed Background\e[0m"
Greed Background颜色码:重置=0,黑色=40,红色=41,绿色=42,黄色=43,蓝色=44,洋红=45,青色=46,白色=47
文字闪动:
echo -e "\033[37;31;5mMySQL Server Stop...\033[39;49;0m"
红色数字处还有其他数字参数:0 关闭所有属性、1 设置高亮度(加粗)、4 下划线、5 闪烁、7 反显、8 消隐
echo -n 不换行输出
echo -e 处理特殊字符
若字符串中出现以下字符,则特别加以处理,而不会将它当成一般文字输出:
\a 发出警告声;
\b 删除前一个字符;
\c 最后不加上换行符号;
\f 换行但光标仍旧停留在原来的位置;
\n 换行且光标移至行首;
\r 光标移至行首,但不换行;
\t 插入tab;
\v 与\f相同;
\ 插入\字符;
\nnn 插入nnn(八进制)所代表的ASCII字符;
举例说明:
$echo -e "a\bdddd" //前面的a会被擦除
$echo -e "a\adddd" //输出同时会发出报警声音
$echo -e "a\ndddd" //自动换行
我们在使用linux的过程中,经常会去下载安装包,下载时候的那个进度提示是不是比较好玩,下载进度的百分比在不断变化,利用echo -e和-n参数我们也可以实现这个效果了。
脚本的基本结构
一个脚本的基本结构是这样的:
#!SHEBANG
CONFIGURATION_VARIABLES
FUNCTION_DEFINITIONS
MAIN_CODE
Shebang
如果可能,请不要忘记shebang。
请小心使用/bin/sh作为shebang,在Linux系统中,/bin/sh就是Bash这是一个错误的观点。
于我而言,shebang有两个目的:
说明直接执行时以哪个解释器来执行;
明确该脚本应该以哪个解释器来执行;
命令替换
正如文章the article about command substitution [Bash Hackers Wiki]中提及的,你应该使用$( .. )形式。
不过,如果可移植性是一个问题,你可能必须使用反引号的形式...。
在任何情况,如果其它展开或者单词分隔并不是你期望的,你应该将命令替换用双引号引起来。
环境变量
变量:全部是大写字母
变量引用:全部以变量名加双引号引用,如”$TERMTYPE”,或“${TERMTYPE}”,如果变量类型是数值型不引用,如:
如果需要从配置文件导出变量,则在变量前加一大写字母,以识别导出变量与自定义环境变量的区别,如:
变量值的引用尽量以$开头,如$(ls inst_.sh),避免使用`ls inst_。sh`
循环控制变量可以命名为单个字母, 比如 i、j等。 也可以是更有意义的名称, 比如 UserIndex。
环境变量和全局变量 在脚本开头定义。
函数中使用较多的文件,以环境变量的形式在文件开头定义,仅函数中使用的变量在函数开头定义
配置变量
在这里,我将这一类变量——可以被用户更改的——叫做配置变量。
让这类变量容易找到,一般放在脚本的头部,给它们有意义的名称并且加上注释说明。正如上面说的,仅当你知道你为什么这么做的时候,才用大写的变量名形式,否则小写形式更加安全。
语句
if 语句
if/then/else 语句中最可能被执行的部分应该放在 then 子句中, 不太可能被执行的部分应该放在 else 子句中。
如果可能, 尽量不要使用一连串的 if 语句, 而应该以 case 语句替代。
不要使 if 语句嵌套超过5层以上, 尽量以更清楚的代码替代。
case 语句
概要
case 语句中的单个子句应该以 case 常数的数字顺序或字母顺序排列。 子句中的执行语句应该尽量保持简单, 一般不要超过4到5行代码。 如果执行语句过于复杂, 应该将它放置在独立的函数中。
case 语句的 *) 子句应该只在正常的默认情况或检测到错误的情况下使用。
格式
case 语句遵循同样的缩进和命名约定。
while 语句
使用 Exit 过程退出 while 循环是不好的; 如果可能, 应该只使用循环条件来结束循环。
while 循环的所有初始化代码应该紧贴在进入 while 循环之前, 不要被其他无关语句分隔开。
循环结束后的处理应该紧跟在循环之后。
for 语句
如果需要执行确定次数的增量循环, 应该用 for 语句替代 while 语句。
参数展开
除非你知道自己做的事情,请在参数展开的地方使用双引号
当然,也有一些地方并不需要使用双引号,例如:
[[ ]]测试表达式内部是不会展开的;
在case $WORD in语法中WORD也不会展开的;
在变量赋值var=$WORD的地方也是不会展开的 但是在这些地方使用引号并不会出错,如果你习惯于在每个可能展开参数的地方使用引号,你写得代码会很安全。
如果你要传递一个参数作为一个单词列表,你可以不使用引号,例如:
list="one two three"
# you MUST NOT quote $list here
for word in $list; do
...
done
分离复合命令
译者注:其实这里的复合命令就是指块语句,例如for/while循环, if分支结构等等。
HEAD_KEYWORD parameters; BODY_BEGIN
BODY_COMMANDS
BODY_END
我习惯于:
将HEAD_KEYWORD和初始化命令或者参数放在第一行;
将BODY_BEGIN同样放在第一行;
复合命令中的BODY部分以2个空格缩进;
BODY_END部分独立一行放在最后;
1)if/then/elif/else分支语句
if ...; then
...
elif ...; then
...
else
...
fi
2)for循环
for f in /etc/*; do
...
done
3) while/until循环
while [[ $answer != [YyNn] ]]; do
...
done
4) case分支语句
case $input in
hello)
echo "You said hello"
;;
bye)
echo "You said bye"
if foo; then
bar
fi
;;
*)
echo "You said something weird..."
;;
esac
几点注意的地方:
如果不是100%需要,匹配部分左右的括号不需要写(译者注:例如写成hello)而不是(hello));
匹配模式与分支的终止符号;;位于同一缩进级别
分支内部的命令多缩进一层;
尽管是可选的,这里还是把最后一个分支的终止符号也写上了;
分隔长行
每行不要超过80字,如果超出,建议用“\”折行,有管道的命令行除外。
如果需要分隔过长的代码,你可以使用下面的任意一种方法:
1) 使用与命令宽度相同的缩进
activate some_very_long_option \
some_other_option
2) 使用2个空格缩进
activate some_very_long_option \
some_other_option
从个人的角度来说,除非有特别的需要,我更倾向于第一种形式,因为它突出“上下两行的内容是一起的”这一联系。
缩进
由于Shell没有很好的编辑环境,所以,建议用四个空格为基数进行缩进,好处在不同的环境下TAB可能代表的空格数不同,造成代码的错乱。用TAB他的优点是速度快方便,可以在编辑的时候也用TAB,但需要转换。
可以在更改编辑器,Windows的就不说了,主要是VIM
:set softtabstop=4
注意不要使用 :set tabstop=4 上面那个是同时把这一个TAB转换为四个空格,而这一条是定义TAB为四个空格,如果到其它编辑器上就会看到默认8个空格的情况,那就会不美观了。
另外将原有的TAB转换为空格,:retab
如果想让刚才的配置永久生效需要改动vim的配置文件 vim ~/.vimrc,更多详细的有用的配置见“VIM配置总结”
代码开头约定
1、第一行一般为调用使用的语言
2、下面要有这个程序名,避免更改文件名为无法找到正确的文件
3、版本号
4、更改后的时间
5、作者相关信息
6、该程序的作用,及注意事项
7、版权与是否开放共享GNU说明
函数约定
函数名称应该采用小写的形式,并且有一个很好的意义。函数名称应该容易让人理解,比如f1这个名称虽然容易输入但是对调试和其它人阅读代码造成了很大的困难,它说明不了任何东西。好的函数名称可以帮助说明代码,而不需要额外的注释。
一个或多或少有趣的是:如果你无意这样做,不要把函数名称命名为常见的命令名,新手往往比较容易将脚本或者函数名命名成test,这样就和UNIX的test命令冲突了。
除非绝对必要,仅使用字母、数字和下划线作为函数名称。
每个函数控制在50-100行,超出行数建议分成两个函数
多次反复调用的程序最好分成函数,可以简化程序,使程序条理更清楚
所有函数定义应该在脚本主要代码执行之前,这样可以给人全局的印象,并且确保所有函数在使用之前它是已知的。
你应该使用可移植性高的函数定义形式,即不带function关键字的形式。
关于注释
程序头应加注版本与功能说明的注释。但程序第一行不能汉字。
程序体中应包含必要的注释,注释说明如下:
单行注释,可以放在代码行的尾部或代码行的上部;
多行注释,用于注解复杂的功能说明,可以放在程序体中,也可以放在代码块的开始部分
代码修改时,对修改的内容要加必要版本注释及功能说明。
命名约定
1.本文档的命名约定是系统配置文件、脚本文件;
2.文件名、变量名、函数名不超过20个字符;
3.命名只能使用英文字母,数字和下划线,只有一个英文单词时使用全拼,有多个单词时,使用下划线分隔,长度较长时,可以取单词前3~4个字母。
4.文件名全部以小写命名,不能大小写混用(通过U盘交换文件时,大小写可能会丢失,即:大写文件名可能会全部变成小写文件名);
5.避免使用Linux的保留字如true、关键字如PWD等(见附表);
远程shell
ssh免密
sshd为了安全,对属主的目录和文件权限有所要求。如果权限不对,则ssh的免密码登陆不生效。
用户目录权限为 755 或者 700,就是不能是77x。
.ssh目录权限一般为755或者700。
rsa_id.pub 及authorized_keys权限一般为644
rsa_id权限必须为600
查看目录属性
ls -ld directoy
文件的默认权限
umask 显示系统预留权限值
vim /etc/bashrc 71行是普通用户的更改,73是超级用户的更改
vim /etc/profile 60行是普通用户的更改,62是超级用户的更改
source /etc/bashrc 刷新bash配置
source /etc/profile 刷新系统配置
6.特殊权限
stickyid 强制位
o+t 之针对目录,当一个目录上有t权限时,这个目录中的文件只能被文件拥有者删除
t=1
chmod o+t directroy
chmod 1777 directory
sgid 粘制位
g+s 针对目录,在目录中创建的文件都自动归属到目录所在组,针对二进制文件,
文件内记录的程序在执行时和执行者的组身份没有关系,而是以二进制文件的所有组的身份执行的
chmod g+s file|directory
chmod 2777 file|directory
suid 冒险位
u+s 针对文件,文件记录动作在执行时是一文件所有人身份执行的,与是谁发起的无关
chmod u+s file
chmod 4777 fileg+s
7.权限列表
*1.acl 指定特定的用户对特定的文件拥有特殊权力
-rw-rwx---+ 1 root root 0 Mar 28 02:39 file
d rwx rwx rwx =777 表示目录的操作权限
- rwx rwx rwx = 777 表示文件的操作权限
printf "%-10s %-8s %-4s\n" 姓名 性别 体重kg
printf "%-10s %-8s %-4.2f\n" 郭靖 男 66.1234
%s %c %d %都是格式替代符
%-10s 指一个宽度为10个字符(-表示左对齐,没有则表示右对齐),任何字符都会被显示在10个字符宽的字符内,如果不足则自动以空格填充
,超过也会将内容全部显示出来。
%-4 2f 指格式化小数,其中,.2指保留2为小数
命令行执行登录并且在目标服务器上执行命令
ssh user@remoteNode "cd /home ; ls"
- 双引号,必须有。如果不加双引号,第二个ls命令在本地执行
- 分号,两个命令之间用分号隔开
脚本的方式
这个正式我想要的方式,在目标服务器上执行批量的命令。
#!/bin/bash
ssh root@fusion1 << remotessh
ll
exit
remotessh
远程执行的内容在“<< remotessh ” 至“ remotessh ”之间,在远程机器上的操作就位于其中,注意的点:<< remotessh,ssh后直到遇到remotessh这样的内容结束,remotessh可以随便修改成其他形式。在结束前,加exit退出远程节点
如果不想日志文件在本机出现可以修改配置
- ssh root@192.168.0.23 > /dev/null 2>&1 << remotessh
grep对匹配结果取反: grep -v "pattem" file > file2。
linux 获取网卡信息
sar -n DEV 2
IFACE:LAN接口
rxpck/s:每秒钟接收的数据包
txpck/s:每秒钟发送的数据包
rxbyt/s:每秒钟接收的字节数
txbyt/s:每秒钟发送的字节数
rxcmp/s:每秒钟接收的压缩数据包
txcmp/s:每秒钟发送的压缩数据包
rxmcst/s:每秒钟接收的多播数据包
sar –n DEV 1 2
命令后面1 2 意思是:每一秒钟取1次值,取2次。
DEV显示网络接口信息
另外,有6个不同的开关:DEV | EDEV | NFS | NFSD | SOCK | ALL ,其代表的含义如下:
● DEV显示网络接口信息。
● EDEV显示关于网络错误的统计数据。
● NFS统计活动的NFS客户端的信息。
● NFSD统计NFS服务器的信息
● SOCK显示套接字信息
● ALL显示所有5个开关
sed
删除最后一行
sed -i '$d' fileName
删除以zx开头,以add结尾的行:
sed '/^zx/{/add$/d}' /etc/sudoers
zx ALL=(ALL) NOPASSWD: /usr/sbin/useradd 被删除
1、删除文档的第一行
sed -i '1d'
2、删除文档的最后一行
sed -i '$d'
3、删除文件中的一行
sed -i '3d'
4、删除文件中包含某个关键字开头的所有行
sed -i '/^QWQ/d'
5、删除文件中包含某个关键字的所有行
sed -i '/QWQ/d'
Linux之使用sed取出IP地址
//匹配IP地址
ip addr|sed -nr 's#^.*inet (.*)/24.*$#\1#gp'
ip addr|awk -F '[ /]+' 'NR==9 {print $3}'
//对调用户名,登录权限
cat /etc/passwd|sed -nr 's#([^:]+)(:.*:)(/.*)#\3\2\1#gp'
可使用分号隔开多个命令
sed -i '4d;5d;56d;78d;82d' abc.txt
awk '{for(i=1;i<=NF;++i) printf $i "\t";printf "\n"}' test.txt
awk '{ $3=""; print $0 }' a.txt
将某列置为空,然后打印所有列。
截取第二行:
ifconfig |sed -n '2p'
sed 批量替换多个文件内容
平常需要替换多个文件里的内容,通过sed命令就可以很方便的替换。
sed -i “s/原字符串/新字符串/g” `grep -rl 原字符串 所在目录`
解释:
1. sed -i : 直接替换文件内容。
2. sed ‘s/要被取代的字串/新的字串/g’ 这种模式是一种替换模式,但是这样是直接输出,不会修改文件;要修改文件,需要加上-i.
3. grep -r 搜索子目录查找, -l 表示输出匹配到的文件名。
4. 反引号“ ,是将里面的字符串当做命令执行。
例子: 替换h目录所有文件的listen ,替换为:listen_new
sed -i ‘s/listen/listen_new/g’ `grep -rl listen ./h/*`
数组
个数:${#OLD_IPS[@]}
获取字符串的长度:
str="hello"
len=${#str}
1、获取数组元素的个数:
array=(bill chen bai hu);
num=${#array[@]} //获取数组元素的个数。
遍历数组就变成非常简单的事情:
for ((i=0;i<num;i++))
{
echo $array[i];
}
获取数组某一个单元的长度就变成了:
${#array[i]}
2、获取数组的所有元素:
${array[*]}
遍历数组就编程了非常简单的事情:
for var in ${array[*]}
do
echo $var;
done
获取数组某一个单元的长度就变成了:
${#var}
linux下的shell运算(加、减、乘、除
2018年06月17日 16:03:58 hxpjava1 阅读数 25917
((i=$j+$k)) 等价于 i=`expr $j + $k`
((i=$j-$k)) 等价于 i=`expr $j -$k`
((i=$j*$k)) 等价于 i=`expr $j \*$k`
((i=$j/$k)) 等价于 i=`expr $j /$k`
Let expressions 执行一个或多个表达式。表达式中的变量前不必有$.如果表达式中包含了空格或其他特殊字符,则必须引起来。
例:let “I = I + 1” 或 let i=i+1
算术运算符指的是可以在程序中实现加、减、乘、除等数学运算的运算符。Shell中常用的数学运算符如下所示。
— +:对两个变量做加法。
— -:对两个变量做减法。
— *:对两个变量做乘法。
— /:对两个变量做除法。
— **:对两个变量做幂运算。
— %:取模运算,第一个变量除以第二个变量求余数。
— +=:加等于,在自身基础上加第二个变量。
— -=:减等于,在第一个变量的基础上减去第二个变量。
— *=:乘等于,在第一个变量的基础上乘以第二个变量。
— /=:除等于,在第一个变量的基础上除以第二个变量。
— %=:取模赋值,第一个变量对第二个变量取模运算,再赋值给第一个变量。
在使用这些运算符时,需要注意到运算顺序的问题。例如输入下面的命令,输出1+2的结果。
echo 1+2
Shell并没有输出结果3,而是输出了1+2。在shell中有三种方法可以更改运算顺序。
— 用expr改变运算顺序。可以用echo `expr 1 +2`来输出1+2的结果,用expr表示后面的表达式为一个数学运算。需要注意的是,`并不是一个单引号,而是“Tab”键上面的那个符号。
— 用let指示数学运算。可以先将运算的结果赋值给变量b,运算命令是b=let 1 + 2。然后用echo$b来输出b的值。如果没有let,则会输出1+2。
— 用$[]表示数学运算。将一个数学运算写到$[]符号的中括号中,中括号中的内容将先进行数学运算。例如命令echo$[1+2],将输出结果3。
下面是一个shell程序实例,实现数学函数S=3(xy)+4x2+5y+6的运算。在程序中以位置变量的方式输入x与y的值。程序的编写步骤如下所示。
在主菜单中打开一个终端。在终端中输入“vim”命令打开VIM。
在VIM中按“i”键进入插入模式,然后输入下面的代码。
代码4-2 数学运算实例:\源文件\04\4.4.sh
#!/bin/bash
#4.4.sh
s=0 #定义一个求和变量,初值为0。
t=`expr$1**$2` #用expr改变运算顺序,求x的y次方。
t=$[t*3] #t乘以3。
s=$[s+t] #结果相加。
t=$[$1**2] #求x的平方。
t=$[t*4] #结果乘以4。
s=$[s+t] #结果相加。
t=`expr$2*5` #求5y的值。
s=$[s+t] #结果相加。
s=$[s+6] #结果加上6。
echo$s #输出结果。
echo$((a%b)) #取余
在这个程序中,需要注意算术运算的写法。如果没有expr或$[]更改运算顺序,则会将运算式以字符串的形式赋值,而不会赋值运算结果。
按“Esc”键返回到普通模式。然后输入“:w 4.4.sh”保存文件。
输入“:q”命令,按“Enter”键退出VIM。
在终端中,输入下面的命令对4.4.sh文件添加可执行权限。
chmod +x 4.4.sh
输入下面的命令运行程序。在命令中需要输入两个参数。
./4.4.sh 2 4
程序会完成S=3(xy)+4x2+5y+6的数学运算并输出结果,结果如下所示。
90
#!/bin/bash
a=10
b=20
val=`expr $a + $b`
echo "a + b : $val"
val=`expr $a - $b`
echo "a - b : $val"
val=`expr $a \* $b`
echo "a * b : $val"
val=`expr $b / $a`
echo "b / a : $val"
val=`expr $b % $a`
echo "b % a : $val"
if [ $a == $b ]
then
echo "a is equal to b"
fi
if [ $a != $b ]
then
echo "a is not equal to b"
fi
ip地址的组成(网络位+主机位)
IP地址采用分层结构;
IP地址是由网络号(net ID)与主机号(host ID)两部分组成的。
根据不同的取值范围,IP地址可以分为五类;IP地址中的前5位用于标识IP地址的类别:
A类地址的第一位为0;
B类地址的前两位为10;
C类地址的前三位为110;
D类地址的前四位为1110;
E类地址的前五位为11110。
实际大多通过子网掩码来区分网络位和主机位,子网掩码跟IP地址一一对应,子网掩码为1的是网络位,为0的是主机位。
如:192.168.1.2 掩码255.255.255.0 。网络位192.168.1 主机位是2
举个例子:比如172.16.2.160/255.255.255.0:
这个IP地址的【网络号】就是172.16.2.0 主机号为 0.0.0.160
划分子网情况
如:172.16.2.160/255.255.255.192(IP地址/掩码)
1010 1100 0001 0000 0000 0010 1010 0000 (二进制)
1111 1111 1111 1111 1111 1111 1100 0000 (子网掩码)
------------------------------------------相"与"(理解成相乘)
1010 1100 0001 0000 0000 0010 1000 0000(172.16.2.128这就是子网号)
1010 1100 0001 0000 0000 0010 1000 0001(172.16.2.129是第一个主机)
1010 1100 0001 0000 0000 0010 1011 1110(172.16.2.190最后一个主机)
1010 1100 0001 0000 0000 0010 1011 1111 广播地址 172.16.2.191
1,将一类ip地址(也就是只确定的网络号的ip)划分为更加小的子网络
(通常得到一个c类ip,如:212.26.220.0最后一组是主机号(最大255),用子网掩码分成更小的网段)
因为掩码的值是连续的1,那么子网掩码的值也就是有规律的:
比如
1000 0000 ---> 128
1100 0000 ---> 192
1110 0000 ---> 224
1111 0000 ---> 240
1111 1000 ---> 248
1111 1100 ---> 252
1111 1110 ---> 254
2,将相邻的网络地址合并成同一逻辑网络比如:
两个C类IP地址215.60.30.0与215.60.31.0与子网掩码255.255.254.0
11010111.00111100.00011110.00000000-->215.60.30.0
11010111.00111100.00011111.00000000-->215.60.31.0
11111111.11111111.11111110.10000000-->255.255.254.0//掩码
11010111.00111100.00011110.00000000-->215.60.30.0//都是该网段
注意:一个错误的理解:子网掩码主要目的是增加了ip数量!!!其实并没有增加!!!
(也不能说没有增加,比如相同的ip不同子网掩码,实际公网是不存在相同的ip,,如果说是两个局域网这种情况,不知道算不算增加了)
补充:
1,只知道ip地址那么只能知道是属于哪一类ip。或者认为没有子网络,比如c类ip,那么前3组是网络号,后面一组是主机号
2,只有知道子网掩码和ip,才能知道具体的网段和主机号
3,相同子网掩码未必是同一网段ip,同一网段的ip必然有相同的子网掩码。
“IP地址/ 数字” 是什么意思?例如 192.168.5.12 / 21
数字是子网掩码位(数),说明子网掩码由21个1组成,即 子网掩码是:
11111111 11111111 11111000 00000000 ,也就是255.255.248.0.
两个数相加:
#!/bin/bash
val=`expr 2 + 2`
grep过滤IP
grep -o "[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]"
grep -E "([0-9]{1,3}\.){3}[0-9]"
grep -E "([0-9]{1,3}\.){3}[0-9]" secure
# echo "--999999999999999999999999" | egrep "-" –color
shell学习30:if判断中各种(-a到-z)选项的意思
[ -a FILE ] 如果 FILE 存在则为真。
[ -b FILE ] 如果 FILE 存在且是一个块特殊文件则为真。
[ -c FILE ] 如果 FILE 存在且是一个字特殊文件则为真。
[ -d FILE ] 如果 FILE 存在且是一个目录则为真。
[ -e FILE ] 如果 FILE 存在则为真。
[ -f FILE ] 如果 FILE 存在且是一个普通文件则为真。
[ -g FILE ] 如果 FILE 存在且已经设置了SGID则为真。 [ -h FILE ] 如果 FILE 存在且是一个符号连接则为真。
[ -k FILE ] 如果 FILE 存在且已经设置了粘制位则为真。
[ -p FILE ] 如果 FILE 存在且是一个名字管道(F如果O)则为真。
[ -r FILE ] 如果 FILE 存在且是可读的则为真。
[ -s FILE ] 如果 FILE 存在且大小不为0则为真。
[ -t FD ] 如果文件描述符 FD 打开且指向一个终端则为真。
[ -u FILE ] 如果 FILE 存在且设置了SUID (set user ID)则为真。
[ -w FILE ] 如果 FILE 如果 FILE 存在且是可写的则为真。
[ -x FILE ] 如果 FILE 存在且是可执行的则为真。
[ -O FILE ] 如果 FILE 存在且属有效用户ID则为真。
[ -G FILE ] 如果 FILE 存在且属有效用户组则为真。
[ -L FILE ] 如果 FILE 存在且是一个符号连接则为真。
[ -N FILE ] 如果 FILE 存在 and has been mod如果ied since it was last read则为真。
[ -S FILE ] 如果 FILE 存在且是一个套接字则为真。
[ FILE1 -nt FILE2 ] 如果 FILE1 has been changed more recently than FILE2, or 如果 FILE1 exists and FILE2 does not则为真。
[ FILE1 -ot FILE2 ] 如果 FILE1 比 FILE2 要老, 或者 FILE2 存在且 FILE1 不存在则为真。
[ FILE1 -ef FILE2 ] 如果 FILE1 和 FILE2 指向相同的设备和节点号则为真。
[ -o OPTIONNAME ] 如果 shell选项 “OPTIONNAME” 开启则为真。
[ -z STRING ] “STRING” 的长度为零则为真。
[ -n STRING ] or [ STRING ] “STRING” 的长度为非零 non-zero则为真。
[ STRING1 == STRING2 ] 如果2个字符串相同。 “=” may be used instead of “==” for strict POSIX compliance则为真。
[ STRING1 != STRING2 ] 如果字符串不相等则为真。
[ STRING1 < STRING2 ] 如果 “STRING1” sorts before “STRING2” lexicographically in the current locale则为真。
[ STRING1 > STRING2 ] 如果 “STRING1” sorts after “STRING2” lexicographically in the current locale则为真。
[ ARG1 OP ARG2 ] “OP” is one of -eq, -ne, -lt, -le, -gt or -ge. These arithmetic binary operators return true if “ARG1” is equal to, not equal to, less than, less than or equal to, greater than, or greater than or equal to “ARG2”, respectively. “ARG1” and “ARG2” are integers.
=====================================================================
基本上和其他脚本语言一样。没有太大区别。不过值得注意的是。[]里面的条件判断。
1、字符串判断
str1 = str2 当两个串有相同内容、长度时为真
str1 != str2 当串str1和str2不等时为真
-n str1 当串的长度大于0时为真(串非空)
-z str1 当串的长度为0时为真(空串)
str1 当串str1为非空时为真
2、数字的判断
int1 -eq int2 两数相等为真
int1 -ne int2 两数不等为真
int1 -gt int2 int1大于int2为真
int1 -ge int2 int1大于等于int2为真
int1 -lt int2 int1小于int2为真
int1 -le int2 int1小于等于int2为真
3、文件的判断
-r file 用户可读为真
-w file 用户可写为真
-x file 用户可执行为真
-f file 文件为正规文件为真
-d file 文件为目录为真
-c file 文件为字符特殊文件为真
-b file 文件为块特殊文件为真
-s file 文件大小非0时为真
-t file 当文件描述符(默认为1)指定的设备为终端时为真
4、复杂逻辑判断
-a 与
-o 或
! 非
结尾
语法虽然简单,但是在SHELL里使用的时候,他的功能变得强大了。
Linux 下查看局域网内所有主机IP和MAC
sed的正则匹配
正则匹配IP和子网掩码
[root@localhost log]# ifconfig |sed -n '2p'
[root@localhost log]# ifconfig |sed -n '2p' | sed -r 's#.*r:(.*) B.*k:(.*)#\1 \2#g'
(.*)表示匹配的项,之后可以用\1取出第一个括号内匹配的内容,\2取出第二个括号内匹配的内容
sed
# STR="MAIL FROM(CCC) TO(DDD)"
#echo $STR | sed -n 's/.*FROM([)]{1,}[)]{1,}).*TO(.∗.∗)/\1-\2/g'p
提取括号里面的内如
STR="MAIL FROM(ABCD) BODY"
echo $STR | sed 's/^.*FROM(.∗.∗).*$/\1/g' # ABCD
STR="MAIL FROM(AB)CD) BODY"
echo $STR | sed 's/^.*FROM([)]\+[)]\+).*$/\1/g' # AB
提取第一个括号和第二个括号里面的内如
STR="MAIL FROM(ABCD) TO(EFGH) BODY"
echo $STR | sed 's/^.*FROM([)]\+[)]\+).*TO([)]\+[)]\+).*$/\1-\2/g' # ABCD-EFGH