第三周笔记总结

第七天
运行脚本的条件:
1、加执行权限或者bash+脚本名
2、写路径(绝对、相对均可) 加执行权限以后,如果没有放在PATH变量下的路径内,运行脚本需要写路径
3、如果不想写路径,可以将脚本放在PATH变量中的任何位置均可,通常放/root/bin下,/bin需要增加创建

脚本调试
只检测脚本中的语法错误
bash -n /path/to/some_script
跟踪调试执行
bash -x /path/to/some_script (+代表有命令,++代表命令套命令)

总结:
如果脚本中命令错误,错误的命令不执行,但是其他的命令均执行
如果脚本中存在语法错误,从语法错误的命令开始往下均不执行,在语法错误之上的命令均执行

变量
引用变量一般加$符号,最好加双引号,如echo “$USER”,命令能识别变量就不加$
例:name=”mage” name这个变量名,存的是mage这个字符串
name=hostname echo $name 显示的是主机名
name=cat /etc/fstab echo $name 格式有问题,没有保留原格式
name=cat /etc/fstab echo “$name” 格式与cat /etc/fstab一样
name1=mage name2=wang name3=$name1 echo $name3 显示的是mage,
此时name1=zhangsir echo $name3 显示的是mage,
如果重新为name3赋值,name3=$name1 echo $name3 显示的时zhangsir

在shell脚本里面,i=100,并没有把它当成数字100,而是把它当成字符串
bash 不支持浮点数(即小数)
变量命名法则:
1、不能使用程序中的保留字:例如if, for
2、只能使用数字、字母及下划线,且不能以数字开头
3、见名知义
4、统一命名规则:驼峰命名法(每个单词的首字母大写是大驼峰,第一个单词的首字母小写,其他单词的首字母大写是小驼峰)

bash中变量的种类
根据变量的生效范围等标准划分下面变量类型:
局部变量:1、生效范围为当前shell进程,对当前shell之外的其它shell进程,包括当前shell的子shell进程均无效,在下级进程里面定义的变量不会影响上级进程的变量。说白了局部变量传不下去也传不上来
例:输入命令bash,相当于开了个子bash
echo $$ 显示的是当前进程的进程编号
echo $PPID 显示的是父进程的进程编号
想看进程关系,输入pstree -p
2、其他终端会话上也无效

变量赋值:name=‘value’
可以使用引用value:
(1) 可以是直接字串; name=“root”
(2) 变量引用:name=”$USER”
(3) 命令引用:name= COMMAND name =$(COMMAND)
变量引用:${name} $name
“”:弱引用,其中的变量引用会被替换为变量值
”:强引用,其中的变量引用不会被替换为变量值,而保持原字符串
显示已定义的所有变量:set
删除变量:unset name 删除name变量

环境(全局)变量:生效范围为当前shell进程及其子进程(只能往下传不能往上传)
子进程的变量可以使用父进程的变量,子进程的变量也可以修改,但是不会影响父进程的变量。
export name=wang 将name变量赋值为wang并定义该变量为全局变量
export 显示的是系统中目前的全部环境变量
declare -x name=xixi 也是定义全局变量
env 显示系统中的全局变量

变量声明、赋值:
export name=VALUE
declare -x name=VALUE
变量引用:$name, ${name}
显示所有环境变量:
env
export
declare -x

echo -e “\e[1;31mstart backup\e[0m” 加颜色
例:编写脚本/root/bin/backup.sh,可实现每日将/etc/目录备份到/root/etcYYYY-mm-dd中
echo -e “\e[1;31mstart backup\e[0m”
sleep 2
cp -av /etc /root/etcdate +%F
echo “backup is finished”

本地变量:生效范围为当前shell进程中某代码片断,通常指函数
特殊变量:$?, $0, $*, $@, $#,$$

bash内建的环境变量:
PATH
SHELL
USER
UID
HOME
PWD
SHLVL shell的嵌套深度
LANG
MAIL
HOSTNAME
HISTSIZE
— 代表前面命令的最后一个参数
如:echo a b c
echo $_ 显示的是c
如:ls /boot /data /root
echo $_ 显示的是/root

只读和位置变量
只读变量:只能读,但不能修改和删除
声明只读变量:
readonly name 例:readonly name=liu
declare -r name 例:declare -r name=liu
只读变量退出再进来就消失了
查看只读变量:
readonly –p
declare -r

()的作用:在当前shell环境下开启一个新空间,shell进程编号未变,小括号里面的变量不影响外面,外面的变量可以影响小括号里面。
加小括号的意思是执行一次小括号里面的命令就完事了
所以将来编脚本的时候如果需要用到一次性的任务,不想影响周边的环境,就可以用小括号写法
如:我只想这一次创建一个权限为000的文件,后面的文件默认权限不变
(umask 666;touch /data/f1)
ll /data/f1
———-. 1 root root 0 Apr 9 22:26 f1
touch f2
ll /data/f2
-rw-r–r–. 1 root root 0 Apr 9 22:26 f2
如:在root家目录下输入:(cd /data;rm -f f3)
意思是执行完删除/data下的f3文件后又返回原目录。

{}的作用:不开启子shell,将影响当前的shell环境,注意{}的写法,前后有空格,且最后有分号
{ name=mage;$name; } 显示wang
echo $name 显示还是wang
()与{}的共同点是将括号内作为一个整体,把括号内的多个命令统一执行
小括号:当前的shell环境下开启一个新空间,shell进程编号未变,小括号里面不影响外面,外面可以影响小括号里面
例题:x=1;echo “pid=$$”;(echo “subpid=$$”;echo “subx=$x”;x=2;echo “sub2x”);echo x=$x
显示的是
pid=51503
subpid=51503
subx=1
sub2x=2
x=1

位置变量:在脚本代码中调用通过命令行传递给脚本的参数
$1, $2, …:对应第1、第2等参数,shift [n]换位置
$0: 命令本身(包括路径及脚本名) 使用软链接运行脚本的时候,$0显示的就是软链接的路径和软链接名,这是特殊需要记忆的
$* 传递给脚本的所有参数,全部参数合为一个字符串
$@: 传递给脚本的所有参数,每个参数为独立字符串
$#: 传递给脚本的参数的个数
$@ $* 只在被双引号包起来的时候才会有差异
set — 清空所有位置变量

例如:编一个脚本arg.sh
echo “1st arg is $1”
echo “2st arg is $2”
echo “3st arg is $3”
echo “all arg is $*”
echo “all arg is $@”
echo “the args number is $#”
echo “the script name is basename $0

输入:arg.sh xxx yy zzzz
显示:
1st arg is xxx
2st arg is yy
3st arg is zzzz
all arg is xxx yy zzzz
all arg is xxx yy zzzz
the arg number is 3
the script is arg.sh
例如:
echo “9st arg is $9”
echo “10st arg is $10”
输入:arg.sh a b c d e f g h i j
显示:9st arg is i
10st arg is a0
如果想表示第十个参数则必须加{},所以应该改成
echo “10st arg is ${10}”

scp f1 wang@172.20.102.77:/home/wang/bin 远程复制,将f1文件复制到ip为172.20.102.77的wang用户的/home/wang/bin下,该网址是桥接网卡的网址
编写一个脚本,脚本的作用是我每次运行这个脚本跟上文件名就能将文件传给wang@172.20.102.77这个用户
vim scp.sh
echo “start copy…”
scp $* wang@172.20.102.77:/home/wang/bin
echo “copy finish”
编写完后chmod +x scp.sh
运行scp.sh /etc/centos-release

$*与$@的区别:只在被双引号包起来的时候才会有差异
例:编写fi.sh和f2.sh
vim f1.sh
echo “f1.sh:all arg are $*”
./f2.sh “$*” “$*”作为一个整体 “$@”不作为一个整体
vim f2.sh
echo “f2.sh:1st arg is $1”
运行f1.sh脚本
f1.sh a b c
显示:
f1.sh:all arg are a b c
f2.sh:1st arg is a b c

例:
vim f1.sh
echo “f1.sh:all arg are $*”
set —
echo “f1.sh:all arg are $*”
运行f1.sh脚本
f1.sh a b c
显示:
f1.sh:all arg are a b c
f1.sh:all arg are

例如:编一个脚本arg.sh
echo “1st arg is $1”
echo “2st arg is $2”
echo “3st arg is $3”
echo “all arg is $*”
echo “all arg is $@”
echo “the args number is $#”
echo “the script name is basename $0
创建一个agr.sh的软链接
ln -s agr.sh link.sh
运行link.sh a b c 注:使用软链接运行脚本的时候,$0显示的就是软链接的路径和软链接名
显示
1st arg is a
2st arg is b
3st arg is c
all arg is a b c
all arg is a b c
the arg number is 3
the script is link.sh

例:
echo “1st arg is $1”
echo “2st arg is $2”
echo “3st arg is $3”
echo “all arg is $@”
echo “the args number is $#”
shift
echo “1st arg is $1”
echo “2st arg is $2”
echo “3st arg is $3”
echo “all arg is $@”
echo “the args number is $#”
shift
echo “1st arg is $1”
echo “2st arg is $2”
echo “3st arg is $3”
echo “all arg is $@”
echo “the args number is $#”
运行arg.sh a b c
1st arg is a
2st arg is b
3st arg is c
all arg is a b c
the arg number is 3
1st arg is b
2st arg is c
3st arg is
all arg is b c
the arg number is 2
1st arg is c
2st arg is
3st arg is
all arg is c
the arg number is 1
总结:shift命令默认将参数左移顶掉一位,可以移多位,shift后面跟上相应的数字即可

退出状态
进程使用退出状态来报告成功或失败
0 代表成功,1-255代表失败
$? 变量保存最近的命令退出状态
例如:
ping -c1 -W1 hostdown &> /dev/null
echo $?
-c1 意思是ping一次

对于脚本来讲,如
hostname
echo “$?” 这个$?显示的是上一条命令的执行结果

如果脚本中有错误命令,如编制脚本f3.sh
histnam
ls
运行f3.sh脚本
echo $? 显示的是0

如果将f3.sh脚本内容变为
ls
hostnam
运行f3.sh脚本
echo $? 显示的不是0
总结:说明脚本运行后查看$?,$?的值是由脚本中最后一条命令决定的,最后一条命令没问题,$?就是0,否则就不是0
如果脚本中存在语法错误,则$?为非0

退出状态码
bash自定义退出状态码
exit [n]:自定义退出状态码 如exit 5 echo “$?”如果成功显示的就是5
注意:脚本中一旦遇到exit命令,脚本会立即终止,后面的命令就不执行了;终止退出状态取决于exit命令后面的数字
注意:如果未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一条命令的状态码

总结:
我们去编制一个脚本的时候就相当于在当前的shell里开启了一个子进程
例如:我们定义一个变量,可以在新建的脚本中显示出来吗?
name=wang
vim f3.sh
echo “f3.sh:$name”
运行f3.sh脚本
显示
f3.sh: 原因是局部变量父不传子,如果name定义为全局变量,就可以显示f3.sh:wang

算术运算
bash中的算术运算:help let
+, -, *, /, %取模(取余), **(乘方)
实现算术运算:
(1) let var=算术表达式 例如:let result=100%3 echo $result 显示的是1,也可以写成result=$[100%3] echo $result let中乘号需要转义
(2) var=$[算术表达式] 例如:m=2 n=3 sum=$[$m+$n] echo $sum 显示的是5 备注:这个公式乘号不需要转义
(3) var=$((算术表达式))
(4) var=$(expr arg1 arg2 arg3 …)例:var=$(expr 1 + 2) echo ${var} 也可以做乘积var=$(expr 1 \* 2) echo $var *需要转义 expr是表达式
(5) declare –i var = 数值 例:declare -i a=10;declare -i b=20;declare -i c=$a+$b;echo $c
(6) echo ‘算术表达式’ | bc
乘法符号有些场景中需要转义,如*(let和expr中乘号需要转义)
bash有内建的随机数生成器:$RANDOM(0-32767)
echo $[$RANDOM%50] :0-49之间随机数

例如:
x=10
y=20
let z=$x+$y
echo $z 显示30

赋值
增强型赋值:
+=, -=, *=, /=, %=
let varOPERvalue
例如:let count+=3
自加3后自赋值
自增,自减:
let var+=2 相当于var=var+2
let var++ 相当于var=var+1
let var-=1
let var–

例:编制colour.sh脚本,将colour打印出来,每次颜色随机
colour=$[RANDOM%7+31]
echo -e “\e[1;${colour}mcolour\e[0m”

通常认为0是假,1是真
&相当于并且,取交集
0&0 0
0&1 0
1&0 0
1&1 1
|相当于或
0|0 0
0|1 1
1|0 1
1|1 1

非:!
!1 = 0
!0 = 1

短路与 &&
短路或 ||
0&&0 0 cmd1&&cmd2 如果cmd1为假,cmd2为真还是为假不影响结果,cmd2不需要执行
0&&1 0
1&&0 0 cmd1&&cmd2 如果cmd1为真,需要执行cmd2
1&&1 1

0||0 0
0||1 1 cmd1||cmd2 如果cmd1为假,需要执行cmd2
1||0 1 cmd1||cmd2 如果cmd1为真,不需要执行cmd2
1||1 1

XOR 异或(如果两个值相同,结果为假,如果两个值不同,结果为真)
0^1=1
0^0=0
1^0=1
1^1=0
异或的时候是二进制计算
例如:
a=2
b=3
let c=$a^$b
echo $c 显示的是1
为什么是1?解析如下
首先需要将2和3转换为二进制,即
10 (2的二进制表示)
11 (3的二进制表示)
01 (对位异或)
所以结果为1

例如
b=4
a=6
let c=$a^$b
echo $c 显示的是2
110 (6的二进制表示)
100 (4的二进制表示)
010 (对位异或) 二进制的10就是十进制的2
延伸:将a和b互换
原始方法找一个临时变量
tmp=$a
a=$b
b=$tmp
通过异或来实现对调a=5 b=6
a=$[a^b];b=$[a^b];a=$[a^b];echo $a $b

练习:
1、编写脚本/root/bin/sumid.sh,计算/etc/passwd文件中的第10个用户和第
20用户的ID之和
x=head -n $1 /etc/passwd | tail -n 1 | cut -d: -f 3
y=head -n $2 /etc/passwd | tail -n 1 | cut -d: -f 3
let z=$x+$y
echo $z
运行sumid.sh 10 20 即可得出结论
2、编写脚本/root/bin/sumspace.sh,传递两个文件路径作为参数给脚本,计
算这两个文件中所有空白行之和
a=sed -r '/^[[:space:]]*$/!d' $1 | wc -l
b=sed -r '/^[[:space:]]*$/!d' $2 | wc -l
let c=$a+$b
echo $c
3、编写脚本/root/bin/sumfile.sh,统计/etc, /var, /usr目录中共有多少个一级
子目录和文件
a=ls -1 $1 | wc -l
b=ls -1 $2 | wc -l
c=ls -1 $3 | wc -l
let d=$a+$b+$c
echo $d

条件测试
判断某需求是否满足,需要由测试机制来实现
专用的测试表达式需要由测试命令辅助完成测试过程
评估布尔声明,以便用在条件性执行中
若真,则返回0
若假,则返回1
测试命令:
test EXPRESSION
[ EXPRESSION ]
[[ EXPRESSION ]]
注意:EXPRESSION前后必须有空白字符

例:str1=aaa str2=bbb 比较下这两个字符串是否相同?
test $str1 = $str2 (注意等号前后有空格)
是否相等,输入echo $?
如果是0则相等,如果是1则不相等
还可以写成
str1=aaa str2=bbb
[ $str1 = $str2 ] (注意中括号内的空格问题)
echo $?

例:判断某个变量是否为空
[ -z $var ] 等价于test -z $var -z意为zero
echo $?
如果为0,则变量var未赋值,如果为1,则变量var有值
例:判断某个变量是否为非空
[ -n $var ] -n可以省略
echo $?
如果显示0则说明var变量有值,如果为1则说明var变量为空
[ “abc” ] echo $?显示的是0
[ “” ] echo $?显示的是1
[] echo $?显示的是1

例:
x=haha;y=xixi;[ $x = $y ] && echo “equal” || echo “no equal”
逻辑关系是如果[ $x = $y ]为真,则执行echo “equal”
如果[ $x = $y ]为假,则执行echo “no equal”

例:
m=10;n=20
[ $m -eq $n ] && echo “equal” || echo “no equal” 数字相比是否相同使用-eq

数值测试:
-gt 是否大于 great
-ge 是否大于等于 great equal
-eq 是否等于 equal
-ne 是否不等于 not equal
-lt 是否小于 little
-le 是否小于等于 little equal

bash的字符串测试
字符串测试:
== 是否等于 特殊:[[ == * ]],这里的*是通背符,代表任意字符串,不是正则表达式中的*
> ascii码是否大于ascii码
< 是否小于
!= 是否不等于
=~ 左侧字符串是否能够被右侧的PATTERN所匹配
注意: 此表达式一般用于[[ ]]中;扩展的正则表达式
-z “STRING“ 字符串是否为空,空为真,不空为假
-n “STRING“ 字符串是否不空,不空为真,空为假
注意:用于字符串比较时用到的操作数都应该使用引号

例如:编制脚本diskcheck.sh检查分区磁盘最大的那个是否大于等于80,如果大于80就报警,显示最大分区占用率
x=df | grep "sda" |tr -s " " "%" | cut -d "%" -f 5 | sort -nr | head -n1
[ “$x” -ge 80 ] && echo “disk full” || echo “disk no full”
echo $x

例:如果光打下面的命令
[ $n -ge 80 ] && echo warning会提示
bash: [: -ge: unary operator expected
因为变量n为空,所以建议加””
[ “$n” -ge 80 ] && echo warning
总结:变量在中括号里面或者与test命令搭配时最好加上双引号,避免提示错误

例:编写脚本/root/bin/sumid.sh,计算/etc/passwd文件中的第10个用户和第
20用户的ID之和。
[ $# -ne 2 ]&& echo “arg are two” && exit
x=head -n $1 /etc/passwd | tail -n 1 | cut -d: -f 3
y=head -n $2 /etc/passwd | tail -n 1 | cut -d: -f 3
z=$[$x+$y]
echo $z
运行sumid.sh 10 20

例如
n=12
[[ “$n” =~ ^[[:digit:]]+ ]] && echo digit || echo “no digit” 引用正则表达式必须是[[]]
n这个变量的值能否被右边的digit匹配到,如果能匹配到执行echo digit,如果匹配不到,执行echo “no digit”
也可以写成[[ “$n” =~ ^[0-9]+$ ]] && echo digit || echo “no digit”

如果写成[[ ! “$n” =~ ^[0-9]+$ ]] && echo digit || echo “no digit”
! “$n” =~ ^[0-9]+$ 表示$n不是数字的话
表示如果”$n” =~ ^[0-9]+$是真,!”$n” =~ ^[0-9]+$就为假,则输出echo “no digit”

例:编写脚本/root/bin/sumid.sh,计算/etc/passwd文件中的第10个用户和第
20用户的ID之和。
[ $# -ne 2 ]&& echo “arg are two” && exit
[[ ! “$1” =~ ^[0-9]+$ ]] && echo “$1 is not digit”&& exit 表示$1不是数字的话,输出$1 is not digit并且退出
[[ ! “$2” =~ ^[0-9]+$ ]] && echo “$2 is not digit”&& exit 表示$2不是数字的话,输出$2 is not digit并且退出
x=head -n $1 /etc/passwd | tail -n 1 | cut -d: -f 3
y=head -n $2 /etc/passwd | tail -n 1 | cut -d: -f 3
z=$[$x+$y]
echo $z

例如:编写f.sh脚本
[[ $f1 =~ .+\.sh$ ]] && echo sh || echo no
保存退出
将f1=a.sh 后运行f1.sh显示no
原因是未将变量f1定义为全局变量,父进程定义的变量值无法传到子进程
以后写脚本的时候尽量不要在脚本中调用父进程的变量,如果要调请将变量定义为全局变量

Bash的文件测试
存在性测试
-a FILE:同-e ,判断文件是否存在 例如:[ -a /etc/fstab ] && echo exist
-e FILE: 文件存在性测试,存在为真,否则为假
存在性及类别测试
-b FILE:是否存在且为块设备文件
-c FILE:是否存在且为字符设备文件
-d FILE:是否存在且为目录文件 例:[ -d /etc/ ] && echo ture [ -d /bin ] && echo ture 显示ture,但是实际不是文件夹是个软链接,需要注意下
-f FILE:是否存在且为普通文件
-h FILE 或 -L FILE:存在且为符号链接文件
-p FILE:是否存在且为命名管道文件
-S FILE:是否存在且为套接字文件
-L FILE:是否为软链接 [ -L /bin ] && echo ture 显示为ture [ -L /bin/ ] && echo ture 没有显示
-w FILE:是否有写权限,以实际权限为准,不是看ll那一栏 如[ -w /etc/shadow ] && echo ture || echo false
-r FILE:是否有读权限
-x FILE:是否有执行权限

例如:想创建用户,但是事先得先判断下用户是否已经存在,如果存在不创建,如果不存在则创建,同时指定用户口令
id $1 &> /dev/null
[ $? -ne 0 ] && useradd $1 || { echo exist ; exit; } 备注:这块必须用大括号,注意大括号的格式,大括号的作用是让括号内的命令作为一个整体且影响整个shell环境,
echo magedu | passwd –stdin $1 如果使用小括号,意味着退出echo那个进程后会继续往下执行其余命令

例如:假如为假我希望两个命令都执行,为真都不执行
false || echo cmd1 && echo cmd2 显示的是cmd1 cmd2
true || echo cmd1 && echo cmd2 显示的是cmd2 这就不对了,有违初衷
如果为真都不执行则
true || { echo cmd1;echo cmd2; }

例如:看看大括号和小括号的区别
false || { echo cmd1;exit; } 显示的是cmd1 logout,退出当前进程,所以写脚本必须用大括号
false || ( echo cmd1;exit ) 显示的是cmd1 退出echo这个进程,后续如果有命令继续执行

例如:-a并且 -o或 -v是否此变量已经被设置
[ -r /etc/issue -a -w /etc/issue ]&& echo “read and write” 意思是判断对/etc/issue能读并且能写,如果为真显示read and write
[ -r /etc/issue -o -w /etc/issue ]&& echo “read or write” 意思是判断对/etc/issue能读或者能写,如果为真显示read or write
[ -v “$var1″ ] && echo set 如果有值显示set
var1=”” [ -v “$var1” ] && echo set || echo “no set” 显示的是no set
电脑认为是赋值了,只不过为空字符串而已

例:判断变量是否为空的方法
[ -z “$var” ]
[ -n “$var” ]
[ “$var” = “” ]
[ x”$var” = “x” ]

使用read命令来接受输入
使用read来把输入值分配给一个或多个shell变量
-p 指定要显示的提示
-s 静默输入,一般用于密码 read -p -s “please input your password:” password passwd前面必须有空格,否则赋不上值
-n N 指定输入的字符长度N read -n 3 name 为name变量赋值最多三个字符
-d‘字符’ 输入结束符 read -d a name 为name赋值,什么时候有a就退出
-t N TIMEOUT为N秒 read – t 5 name 如果五秒钟不输出自动退出
read 从标准输入中读取值,给每个单词分配一个变量
所有剩余单词都被分配给最后一个变量
read -p “Enter a filename: “ FILE

read var1敲回车等待输入,输入的值就是变量var1的值,echo $var1
如:编一个read.sh脚本,功能是提示输入姓名并把姓名显示出来
echo -e “please input you name:\c” \c取消换行符
read name
echo “your name is $name”
或者
read -p “please input your name:” name
echo “your name is $name”
例如:鸡兔同笼,头35 脚94 请问鸡多少只,兔子多少只
read -p “head number:” head
read -p “feet number:” feet
let rabbit=($feet-2\*$head)/2
let chook=$head-$rabbit
echo $chook
echo $rabbit

例如:
read x y z 回车输入a b c
echo $x 显示a
echo $y 显示b
echo $z 显示c

echo a b c > f1
read x y z < f1
echo $x 显示a
echo $y 显示b
echo $z 显示c

f1内存有a b c
read x y z < f1
echo $x 显示a
echo $y 显示b
echo $z 显示c

echo aa bb cc | read x y z
echo $x 显示a
echo $y 显示b
echo $z 显示c

cat > f1
aaa
bbb
ccc
cat f1 | read x y z
echo $x 显示a
echo $y 显示b
echo $z 显示c

cat > f1
aaa
bbb
ccc
read x y z < f1
echo $x 显示aaa
echo $y 没有显示
echo $z 没有显示

read x y z <<< “ii jj kk” 用这种方法好用
echo $x 显示的是ii
echo $y 显示的是jj
echo $z 显示的是kk

第八天
.和source后面一般跟的是配置文件
如:在命令行输入
CMD=”hostname”
echo $CMD 显示的是hostname
$CMD 显示的是centos6.magedu.com(主机名)
如果cmd=hostname
echo $CMD 显示的是centos6.magedu.com(主机名)

如果用于字符串的精确匹配,那么我们一般用[],例如:[ “var” = “haha” ]
如果用正则表达式,则[[]]

如:假设cmd2始终为真
cmd1 || cmd2 && cmd3 如果cmd1为真,cmd2不执行,cmd3执行。如果cmd1为假,执行cmd3
cmd1 && cmd2 || cmd3 如果cmd1为真,不执行cmd3,如果cmd1为假,执行cmd3
如果想cmd1为假,我希望cmd2和cmd3都执行,则
cmd1 || { cmd2;cmd3; }

例如:判断输入是yes还是no
read -p “Do you agree?yes or no:” ans
[[ $ans =~ ^([yY]|[Yy][eE][Ss])$ ]] &&{ echo yes;exit; }
[[ $ans =~ ^([nN]|[Nn][oO])$ ]] && { echo no; exit; }
#[[ $ans =~ ^([^Yy]|[^nN]) ]] && echo please input yes or no:
[[ ! $ans =~ (^([yY]|[Yy][eE][Ss])$ | ^([nN]|[Nn][oO])$) ]] && echo please input yes or no:

bash的配置文件
按生效范围划分,存在两类:
全局配置:
/etc/profile
/etc/profile.d/*.sh
/etc/bashrc
个人配置:
~/.bash_profile
~/.bashrc bashrc相当于bash run command

shell登录两种方式
交互式登录:
(1)直接通过终端输入账号密码登录
(2)使用“su – UserName” 切换的用户
执行顺序:/etc/profile –> /etc/profile.d/*.sh –> ~/.bash_profile –>
~/.bashrc –> /etc/bashrc
非交互式登录:
(1)su UserName
(2)图形界面下打开的终端
(3)执行脚本
(4)任何其它的bash实例
执行顺序: ~/.bashrc –> /etc/bashrc –> /etc/profile.d/*.sh

.和source 与运行脚本bash或者直接执行脚本的区别
source表示在当前shell运行,不是开启子进程
例如: vim f1.sh
name=haha
echo “f1.sh:name=$name”
在父进程定义name=xixi
source f1.sh
显示的是f1.sh:name=haha
echo $name
显示的是haha,并不是xixi
所以:脚本运行用bash或者直接加执行权限,配置文件一般用source或者.立即生效
.vimrc 不是bash的配置文件,所以不能用.或source

默认别名不能放在脚本里面,脚本不支持别名,在脚本里定义别名也失效

Profile类
按功能划分,存在两类:
profile类和bashrc类
profile类:为交互式登录的shell提供配置
全局:/etc/profile, /etc/profile.d/*.sh
个人:~/.bash_profile
功用:
(1) 用于定义环境变量
(2) 运行命令或脚本

Bashrc类
bashrc类:为非交互式和交互式登录的shell提供配置
全局:/etc/bashrc
个人:~/.bashrc
功用:
(1) 定义命令别名和函数
(2) 定义本地变量

Bash 退出任务
保存在~/.bash_logout文件中(用户)
在退出登录shell时运行
用于:创建自动备份和清除临时文件
.bash_logout 存放的是退出的时候做点什么事,例如在.bash_logout存放rm -f /root/dir1/*

$-变量
h:hashall,打开这个选项后,Shell 会将命令所在的路径hash下来,避免每次
都要查询。通过set +h将h选项关闭
i:interactive-comments,包含这个选项说明当前的 shell 是一个交互式的
shell。所谓的交互式shell,在脚本中,i选项是关闭的。
m:monitor,打开监控模式,就可以通过Job control来控制进程的停止、继
续,后台或者前台执行等。
B:braceexpand,大括号扩展 例如echo f{1..10}
H:history,H选项打开,可以展开历史列表中的命令,可以通过!感叹号来完
成,例如“!!”返回上最近的一个历史命令,“!n”返回第 n 个历史命令

练习
1、让所有用户的PATH环境变量的值多出一个路径,例如:/usr/local/apache/bin
vim /etc/profile.d/env.sh
PATH=/etc/profile.d/env.sh:$PATH

etc/sysconfig/network-scripts/ifcfg-ens33 centos7上修改网卡设置的路径
etc/sysconfig/network-scripts/ifcfg-eth0 centos6上修改网卡设置的路径
2、用户root登录时,将命令指示符变成红色,并自动启用如下别名:
rm=‘rm –i’
cdnet=‘cd /etc/sysconfig/network-scripts/’
editnet=‘vim /etc/sysconfig/network-scripts/ifcfg-eth0’
editnet=‘vim /etc/sysconfig/network-scripts/ifcfg-eno16777736 或 ifcfg-ens33 ’ (如果系
统是CentOS7)
答:
PS1=”\[\e[1;31m\][\u@\h \W]\\$\[\e[0m\]”
alias rm=’rm –i’
alias cdnet=’cd /etc/sysconfig/network-scripts/’
alias editnet=’vim /etc/sysconfig/network-scripts/ifcfg-ens33′
3、任意用户登录系统时,显示红色字体的警示提醒信息“Hi,dangerous!”
^[[1;31mHi,dangerous!^[[0m
4、编写生成脚本基本格式的脚本,包括作者,联系方式,版本,时间,描述等
5、编写用户的环境初始化脚本reset.sh,包括别名,登录提示符,vim的设置,
环境变量等
答:vim reset.sh
echo “alias cdnet=’cd /etc/sysconfig/network-scripts/'” >> /etc/profile.d/env.sh
echo “alias editnet=’vim /etc/sysconfig/network-scripts/ifcfg-ens33′” >> /etc/profile.d/env.sh
echo “export name=liubaoyu” >> /etc/profile.d/env.sh
echo ‘PS1=”\[\e[1;32m\][\u@\h \W]\\$\[\e[0m\]”‘ >> /etc/profile.d/env.sh
运行一次reset.sh脚本即可
总结:
1、在初始化的配置文件中如果调用某个脚本,如果脚本中是追加,那么每次启动都会追加一次,导致配置文件内文件多次重复、
2、如果不在初始化配置文件中调用某个脚本,可以编制某个脚本,脚本内将设置内容追加到配置文件内,而且只能运行一次该脚本,否则会重复追加已有内容
3、如果在配置文件中调用脚本,脚本中内容为覆盖,会导致将配置文件中的调用脚本覆盖,而且只留脚本中最后一个命令。
4、也可以在.bash_logout设置删除配置文件的所有内容,然后每次启动手动运行一次reset脚本

bash如何展开命令行
把命令行分成单个命令词
展开别名
展开大括号的声明({}) 例如f{1..10}
展开波浪符声明(~)
命令替换$() 和
再次把命令行分成命令词
展开文件通配(*、?、[abc]等等)
准备I/0重导向(<、>)
运行命令

文件查找和压缩及解压缩
文件查找
在文件系统上查找符合条件的文件
文件查找:locate, find
非实时查找(数据库查找):locate
实时查找:find

locate
查询系统上预建的文件索引数据库(数据库不是实时更新,如果刚建的文件,数据库没有更新则利用locate找不到,可以手动更新updatedb)
/var/lib/mlocate/mlocate.db
依赖于事先构建的索引
索引的构建是在系统较为空闲时自动进行(周期性任务),管理员手动更新数据库(updatedb)
索引构建过程需要遍历整个根文件系统,极消耗资源
工作特点:
查找速度快
模糊查找 locae f1 路径中包含f1都显示
非实时查找
搜索的是文件的全路径,不仅仅是文件名
可能只搜索用户具备读取和执行权限的目录

locate命令
locate KEYWORD
有用的选项
-i 不区分大小写的搜索
-n N 只列举前N个匹配项目
-r 使用正则表达式 在/etc/下搜以.conf结尾的文件: locate -r “^/etc/.*[.]conf$”
示例
搜索名称或路径中带有“conf”的文件
locate conf
使用Regex来搜索以“.conf”结尾的文件
locate -r ‘\.conf$’

find
实时查找工具,通过遍历指定路径完成文件查找
工作特点:
查找速度慢
精确查找
实时查找
可能只搜索用户具备读取和执行权限的目录
对服务器压力较大

find 后面先跟路径,再跟条件及处理动作,find命令自动带递归属性
语法:
find [OPTION]… [查找路径] [查找条件] [处理动作]
查找路径:指定具体目标路径;默认为当前目录
查找条件:指定的查找标准,可以文件名、大小、类型、权限等标准进行;
默认为找出指定路径下的所有文件
处理动作:对符合条件的文件做操作,默认输出至屏幕

查找条件
指搜索层级 默认是递归搜索
-maxdepth level 最大搜索目录深度,指定目录为第1级
例如:find /etc/ -maxdepth 2 -name passwd 查找名为passwd的文件在etc下寻找,最大深度为2
-mindepth level 最小搜索目录深度
例如:find /etc/ -mindepth 2 -name passwd 查找名为passwd的文件在etc下寻找,最小深度为2
例如:find /etc/ -maxdepth 2 -mindepth 2 -name passwd 在etc下第二层目录内寻找名为passwd的文件
根据文件名和inode查找:
-name “文件名称”:
find /data -name f1 精确匹配,寻找data目录下名为f1的文件
find /data -name “*f1*” 模糊匹配,寻找data目录下名包含f1的文件,模糊匹配必须加双引号
支持使用glob:*, ?, [], [^]
-iname “文件名称”:不区分字母大小写
-inum n 按inode(节点编号)号查找 例如: find /data -inum 30 在/data目录下寻找节点编号为30的文件
-samefile name 相同inode号的文件 例如:find /data -samefile f1 在data目录下搜索与f1节点编号相同的文件
-links n 链接数为n的文件 例如:find /data -links 2 在data目录下搜索链接数为2的文件
-regex “PATTERN”:以PATTERN匹配整个文件路径字符串,而不仅仅是文件名称
例如:find /etc -regex “.*[.]conf$” 查找在etc下的以.conf结尾的文件

查找条件
根据属主、属组查找: -ls 是以列表形式显示
-user USERNAME:查找属主为指定用户(UID)的文件
例如:find /home -user liu -ls 在home下查找拥有者为liu的文件并详细显示
find /home -user liu -name “*.sh” -ls 在home下查找拥有者为liu并且为.sh结尾的文件,并以列表形式显示
-group GRPNAME: 查找属组为指定组(GID)的文件
-uid UserID:查找属主为指定的UID号的文件
-gid GroupID:查找属组为指定的GID号的文件
-nouser:查找没有属主的文件 find /home -nouser -ls
-nogroup:查找没有属组的文件
例如:
find /home -nouser -nogroup -ls 在home下搜索既没有所有者也没有所属组的文件
find /home -nouser -ls -o -nogroup -ls 在home下搜索没有所有者或者没有所属组的文件
等价于find /home \( -nouser -o -nogroup \) -ls
-a 并且的意思,可以省略

查找条件
根据文件类型查找:-type TYPE
f: 普通文件
d: 目录文件
l: 符号链接文件
s:套接字文件
b: 块设备文件
c: 字符设备文件
p: 管道文件
空文件或目录:-empty 例如:find /app -type d -empty
例如 find /home -type -d -ls 搜索home下的文件夹并详细显示出来(默认递归了)
如果我只想搜索home下的文件夹,不想递归,则
find /home -type d -maxdepth 1 -ls

查找条件
组合条件:
与:-a
或:-o
非:-not, !
例如:find /home -empty -not -type f -ls 在home下搜索空的但不是普通文件,并详细显示
find /home !-empty -type f -ls 非空的并且是普通的文件
德·摩根定律:
(非 A) 或 (非 B) = 非(A 且 B)
(非 A) 且 (非 B) = 非(A 或 B)
示例:
!A -a !B = !(A -o B)
!A -o !B = !(A -a B)

例如
find /home ! -empty ! -type f 非空并且不是普通文件
等价find /home ! \( -empty -o -type f \) find命令中()需要转义

find -name snow.png 搜索名为snow.png的文件
find -iname snow.png 搜索名忽略大小写,名为snow.png的文件
find / -name “*.txt” 在/下搜索以.txt结尾的文件
find /var –name “*log*” 在var下搜索路径包含log的文件
find -user joe -group joe 搜索所有者为joe并且所属组为joe的文件
find -user joe -not -group joe 搜索所有者为joe,并且所属组不是Joe的文件
find -user joe -o -user jane 搜索所有者为joe或者所有者为jane的文件
find -not \( -user joe -o -user jane \) 搜索所有者不是Joe并且所有者不是Jane的文件
find / -user joe -o -uid 500 搜索所有者为Joe或者uid为500的人的文件

找出/tmp目录下,属主不是root,且文件名不以f开头的文件
find /tmp \( -not -user root -a -not -name ‘f*’ \) -ls
find /tmp -not \( -user root -o -name ‘f*’ \) –ls
排除目录
示例:
查找/etc/下,除/etc/sane.d目录的其它所有.conf后缀的文件
find /etc -path “/etc/sane.d” -a –prune -o -name “*.conf”
查找/etc/下,除/etc/sane.d和/etc/fonts两个目录的所有.conf后缀的文件
find /etc \( -path “/etc/sane.d” -o -path “/etc/fonts” \) -a prune -o -name “*.conf”

查找条件
根据文件大小来查找:
-size [+|-]#UNIT
常用单位:k, M, G,c(byte)
#UNIT: (#-1, #]
如:6k 表示(5k,6k]
-#UNIT:[0,#-1]
如:-6k 表示[0,5k]
+#UNIT:(#, ∞ )
如:+6k 表示(6k ,∞ )

查找条件
根据时间戳:
以“天”为单位;
-atime [+|-]#,
#: [#,#+1)
+#: [#+1, ∞ ]
-#: [0,#)
-mtime
-ctime
以“分钟”为单位:
-amin
-mmin
-cmin

条件查找
根据权限查找:-perm [/|-]MODE
MODE: 精确权限匹配
/MODE:任何一类(u,g,o)对象的权限中只要能一位匹配即可,或关系,+从centos7开始淘汰
如:find -perm /666 -ls 搜索(u,g,o)只要有一个满足6就可以
-MODE:每一类对象都必须同时拥有指定权限,与关系
如:find -perm -666 -ls 表示所有者包含6权限,并且所属组包含6权限,并且other包含6权限,包含即可,并不是精确匹配,如果有文件的权限是777也能搜索出来
666的意思是
110 110 110 是1就检查,0表示不关心,不检查
find -perm 755 会匹配权限模式恰好是755的文件
只要当任意人有写权限时,find -perm +222就会匹配
只有当每个人都有写权限时,find -perm -222才会匹配
只有当其它人(other)有写权限时,find -perm -002才会匹配

处理动作
-print:默认的处理动作,显示至屏幕
-ls:类似于对查找到的文件执行“ls -l”命令
-delete:删除查找到的文件
-fls file:查找到的所有文件的长格式信息保存至指定文件中
find -perm /222 -fls /root/f2.log 将搜索出来的信息存放在f2.log文件内
-ok COMMAND {} \; 对查找到的每个文件执行由 COMMAND 指定的命令,对于每个文件执行命令之前,都会交互式要求用户确认
-exec COMMAND {} \; 对查找到的每个文件执行由COMMAND指定的命令,即批量处理
{}: 用于引用查找到的文件名称自身
find传递查找到的文件至后面指定的命令时,查找到所有符合条件的文件一次性传递给后面的命令
find -name “f*” -ok rm {} \; rm与find命令配合,{}代表前面搜索出来的内容,带ok选项必须以\;结尾
意思是搜索以f开头的文件并删除,且删除时要求用户确认,输入y删除
find -name “f*” -exec rm {} \; 批量执行删除命令不再询问
find -name “f*” -ok mv {} /mnt/ \; 将搜索出来的文件移动到mnt文件夹内
find -name “f*” -ok mv {} {}.bak \; 将搜索出来的文件改名为.bak后缀
find -name “f*” -ok cp {} /data/{}.org \; 将搜索出来的文件复制到data目录下并改名为.org后缀

参数替换xargs
由于很多命令不支持管道|来传递参数,而日常工作中有这个必要,所以就有了
xargs命令
xargs用于产生某个命令的参数,xargs 可以读入 stdin 的数据,并且以空格符
或回车符将 stdin 的数据分隔成为arguments
注意:文件名或者是其他意义的名词内含有空格符的情况
有些命令不能接受过多参数,命令执行可能会失败,xargs可以解决
示例:
ls f* |xargs rm
find /sbin -perm +700 |ls -l 这个命令是错误的
find /sbin -perm +7000 | xargs ls –l
find和xargs格式:find | xargs COMMAND
echo f{1..10000000} | xargs -n 100 touch -n 100的意思是每100个为一行传给touch
echo f{1..10000000} | xargs -n 100 rm -f

find示例
备份配置文件,添加.orig这个扩展名
find -name “*.conf” -exec cp {} {}.orig \;
提示删除存在时间超过3天以上的joe的临时文件
find /tmp -ctime +3 -user joe -ok rm {} \;
在家目录中寻找可被其它用户写入的文件并将写权限去掉
find ~ -perm -002 -exec chmod o-w {} \;
查找/data下的权限为644,后缀为sh的普通文件,增加执行权限
find /data –type f -perm 644 -name “*.sh” –exec chmod 755 {} \;
查看/home的目录
find /home –type d -ls

压缩、解压缩及归档工具(解压缩对后缀要求很严)
file-roller 在图形界面terminal内输入file-roller,是图形化的压缩解压缩
compress/uncompress: .Z
gzip/gunzip: .gz
bzip2/bunzip2: .bz2
xz/unxz: .xz
zip/unzip
tar
cpio

压缩:压缩的是文件,可以一次压缩多个文件,但是压缩结果也是多个,不会打包成一个文件
compress/uncompress
compress [-dfvcVr] [-b maxbits] [file …] 默认不仅压缩而且还会把原文件删除
-d: 解压缩,相当于uncompress
-c: 结果输出至标准输出,不删除原文件 (即压缩完后并没有放到文件里面,而是在屏幕显示)
compress -c f1 > f1.Z 相当于压缩,但会保留原文件
-v: 显示详情
uncompress 解压缩
zcat file.Z >file 使用zcat解压缩,然后重定向到文件里

gzip/gunzip
gzip [OPTION]… FILE … 默认不仅压缩而且还会把原文件删除
-d: 解压缩,相当于gunzip
-c: 将压缩或解压缩的结果输出至标准输出(即压缩完后并没有放到文件里面,而是在屏幕显示)
gzip -c f1 > f1.gz 相当于压缩,但会保留原文件
-#:1-9,指定压缩比,值越大压缩比越大
zcat:不显式解压缩的前提下查看文本文件内容
实例:
gzip -c messages >messages.gz
gzip -c -d messages.gz > messages
zcat messages.gz > messages

bzip2/bunzip2/bzcat 默认不仅压缩而且还会把原文件删除
bzip2 [OPTION]… FILE …
-k: keep, 保留原文件
-d:解压缩
-#:1-9,压缩比,默认为9
bzcat:不显式解压缩的前提下查看文本文件内容
bzcat f1.bz2 > f1

xz/unxz/xzcat
xz [OPTION]… FILE …
-k: keep, 保留原文件
-d:解压缩
-#:1-9,压缩比,默认为6
xzcat: 不显式解压缩的前提下查看文本文件内容

zip/unzip
打包压缩
zip –r /testdir/sysconfig /etc/sysconfig/ 把后面的文件夹压缩到前面的文件内
zip m.zip mmm 将mmm文件压缩到m.zip内 文件不用r,文件夹用r
解包解压缩
unzip sysconfig.zip
cat /var/log/messages | zip messages –
unzip -p message > message

压缩能力排比:.xz>.bz2>.gz>.zip>.Z

tar工具
tar(Tape ARchive,磁带归档的缩写)
tar [OPTION]…
(1) 创建归档
tar -cpvf /PATH/TO/SOMEFILE.tar FILE… 将后面的多个文件打包到/PATH/TO/SOMEFILE.tar里去
-c:打包 -f:打包到哪个文件里 -v:看到过程 -p:保留原有属性
(2) 追加文件至归档: 注:不支持对压缩文件追加
tar -r -f /PATH/TO/SOMEFILE.tar FILE… 将FILE文件追加到归档文件内
(3) 查看归档文件中的文件列表
tar -t -f /PATH/TO/SOMEFILE.tar
(4) 展开归档
tar -x -f /PATH/TO/SOMEFILE.tar 默认在当前目录下解包解包
tar -x -f /PATH/TO/SOMEFILE.tar -C /PATH/ 解包到指定/PATH/目录内,跟-C选项
(5) 结合压缩工具实现:归档并压缩
-j: bzip2, -z: gzip, -J: xz
tar -zcpvf data.tar.gz /data 将/data目录打包并压缩为 data.tar.gz
tar -xvf data.tar.gz -C /mnt 将data.tar.gz 解压到/mnt下

-T选项指定输入文件,-X选项指定包含要排除的文件列表
tar -zcvf mybackup.tgz -T /root/includefilelist -X /root/excludefilelist
分割大的 tar 文件为多份小文件:
split –b Size –d tar-file-name prefix-name
split -b 1M –d mybackup.tgz mybackup-parts 将mybackup.tgz文件切割成每个大小为1M的,每个小文件的前缀名称为mybackup-parts,后缀为数字。-d代表数字,不加-d则后缀为英文字母
split -b 1M mybackup.tgz mybackup-parts
合并:cat mybackup-parts* > mybackup.tar.gz

例如:
vim list.txt
/etc/
/boot/
vim exlist.txt
/etc/shadow
/boot/initramfs
tar -Jcpvf list.tar.xz -T list.txt -X exlist.txt 打包打包文件列表中的文件,但是排除掉排除打包列表中的文件,打包并压缩为list.tar.xz

例如:
tar -tf data.tar
data/
data/.log
data/.f2.swp
data/test.txt
data/.fstab.swp
data/.f1.swp
data/dir1/
data/48_scp.sh
data/f1

tar -tvf data.tar
drwxr-xr-x root/root 0 2018-04-12 16:32 data/
-rw-r–r– root/root 0 2018-03-31 11:54 data/.log
-rw-r–r– root/root 12288 2018-04-07 16:54 data/.f2.swp
-rw-r–r– root/root 10 2018-04-07 17:20 data/test.txt
-rw-r–r– root/root 12288 2018-04-07 18:00 data/.fstab.swp
-rw-r–r– root/root 12288 2018-04-07 18:53 data/.f1.swp
drwxr-xr-x root/root 0 2018-04-08 16:32 data/dir1/
-rwxr-xr-x root/root 93 2018-04-09 11:55 data/48_scp.sh
-rw-r–r– root/root 0 2018-04-12 16:32 data/f1

du -sh /root 查看大小

cpio
功能:复制文件从或到归档
cpio命令是通过重定向的方式将文件进行打包备份,还原恢复的工具,它可以
解压以“.cpio”或者“.tar”结尾的文件
cpio [选项] > 文件名或者设备名
cpio [选项] < 文件名或者设备名
选项
-o 将文件拷贝打包成文件或者将文件输出到设备上
-i 解包,将打包文件解压或将设备上的备份还原到系统
-t 预览,查看文件内容或者输出到设备上的文件内容
-v 显示打包过程中的文件名称。
-d 解包生成目录,在cpio还原时,自动的建立目录
-c 一种较新的存储方式
例如:
将etc目录备份:
find /etc -print |cpio -ov >etc.cpio -print可有可无
内容预览
cpio –tv < etc.cpio
解包文件
cpio –idv < etc.cpio 打包的时候如果带绝对路径那么解包就解到原来路径

文本处理工具sed
Stream EDitor, 行编辑器
sed是一种流编辑器,它一次处理一行内容。处理时,把当前处理的行存储在临时
缓冲区中,称为“模式空间”(pattern space),接着用sed命令处理缓冲区中的
内容,处理完成后,把缓冲区的内容送往屏幕。然后读入下行,执行下一个循环。
如果没有使诸如‘D’的特殊命令,那会在两个循环之间清空模式空间,但不会清
空保留空间。这样不断重复,直到文件末尾。文件内容并没有改变,除非你使用重
定向存储输出。
功能:主要用来自动编辑一个或多个文件,简化对文件的反复操作,编写转换程序等
参考: http://www.gnu.org/software/sed/manual/sed.html

sed工具
用法:
sed [option]… ‘script’ inputfile… 默认自动打印到屏幕上
常用选项:
-n:不输出模式空间内容到屏幕,即不自动打印
-e: 多点编辑(即操作多次) 例如:sed -n -e ‘2p’ -e ‘6p’ f1 显示f1中第二行和第六行
-f:/PATH/SCRIPT_FILE : 从指定文件中读取编辑脚本
例如:cat > sedscript.txt
2~2p
sed -n -f sedscript.txt f1 相当于把”中的条件放到文件中,从文件中调取
-r: 支持使用扩展正则表达式(默认支持基本正则表达式)
-i.bak: 备份文件并原处编辑
script:’地址命令’

sed工具
地址定界:
(1) 不给地址:对全文进行处理
(2) 单地址:
#: 指定的行,$:最后一行
/pattern/:被此处模式所能够匹配到的每一行
(3) 地址范围:
#,# 10,20 从第10行到第20行
#,+# 10,+15 从第10行到第25行
/pat1/,/pat2/ 从满足pat1的行开始到满足pat2的行结束
#,/pat1/ 从第#行开始到满足pat1的行结束
(4) ~:步进
1~2 奇数行 sed -n ‘1~2p’ f1 显示f1文件中的奇数行
2~2 偶数行 sed -n ‘2~2p’ f1 显示f1文件中的偶数行

编辑命令:
d: 删除模式空间匹配的行,并立即启用下一轮循环 例如:sed ‘2d’ f1 将f1中的第二行删除
p:打印当前模式空间内容,追加到默认输出之后
a [\]text:在指定行后面追加文本(实际并没有追加,只是显示出来而已,想真正追加配合i.bak选项) sed ‘2,5a===’ f1 在第二行到第五行后面追加===
支持使用\n实现多行追加
i [\]text:在行前面插入文本 \表示开始的意思,\线后面全是追加的内容
c [\]text:替换行为单行或多行文本
w /path/somefile: 保存模式匹配的行至指定文件
r /path/somefile:读取指定文件的文本至模式空间中匹配到的行后
=: 为模式空间中的行打印行号 例如:sed -n ‘/root/=’ /etc/passwd 将匹配到的行号显示出来
!:模式空间中匹配行取反处理 例如:sed ‘2!d’ f1 将f1中的除了第二行都删了

例如:seq 5 > f1
cat f1
1
2
3
4
5

sed ‘2p’ f1
1
2
2
3
4
5

sed -n ‘2p’ f1
2
ifconfig ens33 | sed -n ‘2p’
inet 192.168.30.142 netmask 255.255.255.0 broadcast 192.168.30.255

在/etc/passwd下搜索包括root的行并显示
sed -n ‘/root/p’ /etc/passwd
在/etc/passwd下搜索以root开头的行
sed -n ‘/^root/p’ /etc/passwd
在/etc/passwd中搜索以b开头为开始到以f开头的行结束
sed -n ‘/^b/,/^f/p’ /etc/passwd

例如:sed ‘2,5a===’ f1 在第二行到第五行后面追加===
1
2
===
3
===
4
===
5
===

例如:在.bashrc里面追加一个别名
sed ‘/aliases/aalias p=poweroff’ ./.bashrc(并没有真正追加,只是显示出来而已,想实现真正追加需要配合i.bak选项)
sed -i.bak ‘/aliases/aalias p=poweroff’ .bashrc(真正追加,并且将原文件备份为.bak后缀的文件)
sed -i.bak2 ‘/aliases/aalias cdnet=”cd /etc/sysconfig/network-scripts/”‘ .bashrc

如果我想在f1文件内第2到第5行后面加空格,如何实现?(在a后面加个\线,\线表示开始,后面全是加的东西)
sed ‘2,5a\ ===’ f1
1
2
===
3
===
4
===
5
===

如果我想在f1文件内第2到第5行前面加空格,如何实现?(在i后面加个\线,\线表示开始,后面全是加的东西)
sed ‘2,5i\ —‘ f1
1

2

3

4

5

如果我想在f1文件内将第2到第4行替换为空格,如何实现?(在c后面加个\线,\线表示开始,后面全是加的东西)
sed ‘2,5c\ —‘ f1
1

5

sed ‘2,5w f2’ f1 将f1文件中满足第2到第5行条件的存到f2文件中
cat f2
2
3
4
5

sed ‘2,5r /etc/issue’ f1 将issue文件中的内容读入到f1文件的第二行到第五行的后面 并没有真正追加,若想真正追加则使用-i.bak.选项
1
2
\S
Kernel \r on an \m
3
\S
Kernel \r on an \m
4
\S
Kernel \r on an \m
5
\S
Kernel \r on an \m

延伸:将别名放到一个文件里,利用sed ‘r’ 就可以一次性读入

sed工具
s///:查找替换,支持使用其它分隔符,s@@@,s###
替换标记:
g: 行内全局替换
p: 显示替换成功的行
w /PATH/TO/SOMEFILE :将替换成功的行保存至文件中

例如:
sed ‘s/root/administrator/’ /etc/passwd 将passwd文件中的第一个root替换为administrator
未加地址表示全文搜索,并没有真正替换,没有加-i.bak选项,只是显示下
sed ‘s/root/administrator/g’ /etc/passwd 将passwd文件中所有root替换为administrator
例如:
sed -r ‘s/(root)/\1er/g’ /etc/passwd 将passwd文件中所有的root替换为rooter
-r 支持扩展的正则表达式
sed -r ‘s/(root)/admini\1/g’ /etc/passwd 将passwd文件中所有的root替换为adminiroot
sed -r ‘s@(GRUB_CMDLINE_LINUX.*)(“)$@\1 xyz\2@g’ /etc/default/grub 在grub文件中在”前面加上空格xyz
或者sed -r ‘/GRUB_CMDLINE_LINUX/s/(.*)”$/\1 xyz”/g’ /etc/default/grub /GRUB_CMDLINE_LINUX为搜索条件
或者sed -r ‘/GRUB_CMDLINE_LINUX/s/”$/ xyz”/g’ /etc/default/grub
GRUB_TIMEOUT=5
GRUB_DISTRIBUTOR=”$(sed ‘s, release .*$,,g’ /etc/system-release)”
GRUB_DEFAULT=saved
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT=”console”
GRUB_CMDLINE_LINUX=”crashkernel=auto rhgb quiet xyz”
GRUB_DISABLE_RECOVERY=”true”

利用sed命令取centos7网卡地址
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.30.142 netmask 255.255.255.0 broadcast 192.168.30.255
inet6 fe80::175d:f288:288e:96d2 prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:69:a0:d0 txqueuelen 1000 (Ethernet)
RX packets 3390 bytes 310820 (303.5 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 2243 bytes 324571 (316.9 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
答:ifconfig ens33 | sed -n ‘2p’ | sed -r ‘s/.*inet (.*) net.*/\1/g’
或者ifconfig ens33 | sed -n ‘2p’ | sed -r ‘s/(.*inet )(.*)( net.*)/\2/g’
或者ifconfig ens33 | sed -r ‘2!d;s/(.*inet )(.*)( net.*)/\2/g’ 除了第二行都删掉,取地址
或者ifconfig ens33 | sed -n ‘2p’ | sed ‘s/.*inet //’ | sed ‘s/ netmask.*//’
或者ifconfig ens33 | sed -n ‘2p’ | sed -e ‘s/.*inet //’ -e ‘s/ netmask.*//’

将/etc/httpd/conf/httpd.conf文件中的第990行和1003到1009行的#删除
cat -n /etc/httpd/conf/httpd.conf | sed -r ‘1003,1009s/#//g’ | sed -r ‘990s/#//g’
cat -n /etc/httpd/conf/httpd.conf | sed -n -e ‘990p’ -e ‘1003,1009p’ | sed ‘s/.*#//g’
cat -n /etc/httpd/conf/httpd.conf | sed -e ‘990,1009!d’ -e ‘991,1002d’| sed ‘s/.*#//g’
cat -n /etc/httpd/conf/httpd.conf | sed ‘990,1009!d’ | sed ‘2,13d’ | sed -r ‘s/.*#//g’ ‘2,13d’代表从管道左侧传过来的第2行到第13行删除

取/etc/sysconfig/network/的基名和目录名
echo “/etc/sysconfig/network/” | sed -r ‘s/(.*\/)([^/].*\/?$)/\1/g’
echo “/etc/sysconfig/network/” | sed -r ‘s/(.*\/)([^/].*\/?$)/\2/g’
示例
sed ‘2p’ /etc/passwd
sed –n ‘2p’ /etc/passwd 只打印第二行
sed –n ‘1,4p’ /etc/passwd 打印1到4行
sed –n ‘/root/p’ /etc/passwd 打印包含root的行
sed –n ‘2,/root/p’ /etc/passwd 打印从2行开始到包含root的行结束
sed -n ‘/^$/=’ file 显示空行行号
sed –n –e ‘/^$/p’ –e ‘/^$/=’ file 空行显示并且显示空行行号
sed ‘/root/a\superman’ /etc/passwd 行后追加\superman
sed ‘/root/i\superman’ /etc/passwd 行前追加\superman
sed ‘/root/c\superman’ /etc/passwd 代替行
sed ‘/^$/d’ file 删除空行
sed ‘1,10d’ file 删除1到10行
cat /etc/passwd | sed ‘2,5d’ 删除2到5行
cat /etc/passwd | sed ‘2a tea’在第二行后面追加tea
sed ‘s/test/mytest/g’ example 将全文中的test替换为mytest
sed –n ‘s/root/&superman/p’ /etc/passwd 单词后
sed –n ‘s/root/superman&/p’ /etc/passwd 单词前
sed -e ‘s/dog/cat/’ -e ‘s/hi/lo/’ pets 多点替换
sed –i.bak ‘s/dog/cat/g’ pets 改了并备份

本文来自投稿,不代表Linux运维部落立场,如若转载,请注明出处:http://www.178linux.com/96013

发表评论

登录后才能评论

This site uses Akismet to reduce spam. Learn how your comment data is processed.

联系我们

400-080-6560

在线咨询:点击这里给我发消息

邮件:1823388528@qq.com

工作时间:周一至周五,9:30-18:30,节假日同时也值班