编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

shell之sed流编辑器06/06,晓桂科技

wxchong 2024-10-17 17:04:35 开源技术 15 ℃ 0 评论

一.sed --流编辑器

1. sed简介

Sed:Stream Editor 流式编辑器 又称行编辑器,每次只编辑一行。Sed工作是在“模式空间”中进行的,并不操作源文件。对源文件无危害。

工作流程:

文件 --> 内存 --> 编辑 --> 标准输出/保存到文件

2.sed使用格式

sed [OPTION]... {script-only-if-no-other-script} [input-file]...

常用选项(OPTION):

-n:只显示sed匹配到的行。其余行不显示。

-i:可以直接操作原文件。默认情况下sed不会改变原文件,但是-i选项可以修改原文件,此选项应慎用。

-r:可以使用标准正则表达式。默认情况下sed只支持基本正则表达式,但是加上-r选项后则支持扩展正则表达式

-e:可以同时执行多个命令

常用格式:

(1)Sed [options] 'script' input_file……

(2)Sed [options] -f script_file input_file……

(3)Sed [options] 'ADDR1,ADDR2command' input_file……

(4)Sed [options] '/PATTERN/command' input_file……

(5)Sed '/PATTERN1/,/PATTERN2/command' input_file……

3. 常用命令(command)

3.1 打印p(print)

# sed -n '3p' /etc/passwd --打印第3行

# sed -n '1,3p' /etc/passwd --打印第1到第3行

# sed -n '1,$p' /etc/passwd

# nl /etc/passwd | sed -n '5,7p' --打印第5到第7行

# head -5 /etc/passwd |sed -ne '1p;4p' --打印第1行和第4行

# nl /etc/passwd | sed -n '/root/p' --查找包含root的行

# cat /etc/passwd | sed -n '/^root/p'

# ifconfig eth1 | sed -n '2p' | awk -F: '{print $2}' | awk '{print $1}' --截取ip

# head -5 /etc/passwd |sed -ne '/^[[:upper:]]/p;/^[a-z]/p' --分别打印大写字母开头的行和小写字母开头的行

# head -5 /etc/passwd |sed -ne '/^[[:upper:]]/,/^[a-z]/p' --用正则表达式实现范围打印

# head -5 /etc/passwd |sed -ne '/^[[:upper:]]/,/nologin$/p'

# head -5 /etc/passwd |sed -n '/^[^[:blank:]]/p' --打印非空格开头的行

比较awk

head -5 /etc/passwd |cat -n | sed -n '1,4p'

head -5 /etc/passwd |cat -n | awk 'NR<5 {print $0}'

head -5 /etc/passwd |cat -n | sed -n '1p;3p;5p'

head -5 /etc/passwd |cat -n | awk 'NR==1 || NR==3 || NR==5 {print $0}'

head -5 /etc/passwd |cat -n | sed -n '/root/p;/daemon/p;/lp/p'

head -5 /etc/passwd |cat -n | awk '$0~"root" || $0~"daemon" || $0~"lp" {print $0}'

3.2 删除用法,以行为单位d(delete)

sed的语法:

sed '范围d' file

如果不指定范围,默认范围是整个文件。

实例:

# sed '1d' /etc/passwd --删除第一行,第二行2d,第三行3d,以此类推,最后一行$d

# sed '1,3d' /etc/passwd --删除第1行到第3行,中间是逗号

# sed '1d;3d' /etc/passwd --删除第1行和第3行,中间是分号

# sed -e '1d' -e '3d' /etc/passwd --删除第1行和第3行

# sed --expression='1d' --expression='3d' /etc/passwd

# sed '/^root/d' /etc/passwd --使用正则表达式,要加双斜杠

# sed '/root/,/sync/d' /etc/passwd --删除包含root到sync的行

# sed '/root/!d' /etc/passwd --!表示后面的命令对所有没有被选定的行发生作用

# head -5 /etc/passwd |cat -n |sed '2d' --指定删除第二行

# head -5 /etc/passwd |cat -n |sed '2,3d' --删除第二行到第三行,中间为逗号,表示范围

# head -5 /etc/passwd |cat -n |sed '1d;5d' --删除第一行和第五行,中间为分号,表示单独的操作

# head -5 /etc/passwd |cat -n |sed '1d;5d;3d'

# head -5 /etc/passwd |cat -n |sed '1,3d;5d'

# head -5 /etc/passwd |sed '/daemon/d'

练习:把上面的使用awk来实现,做对比

# head -5 /etc/passwd |cat -n |awk 'NR!=2 {print $0}'

# head -5 /etc/passwd | nl | awk 'NR!=2 && NR!=3{print $0}'

# head -5 /etc/passwd |awk 'NR!=1 && NR!=3 && NR!=5 {print $0}' --删除第三行和第五行

# head -5 /etc/passwd |cat -n |awk 'NR<3 || NR>5 {print $0}' --删除第三行到第五行

# head -5 /etc/passwd |awk '$0!~"daemon" {print $0}' --和上面sed使用正则表达式一样,awk用匹配来实现有daemon关键字的行就删除

--利用正则表达式来匹配行

# head -n 5 /etc/passwd |cat -n |sed -e '/oo/d' --删除匹配oo的行

# head -n 5 /etc/passwd |sed -e '/^root/d' --删除以root开头的行

# head -n 5 /etc/passwd |sed -e '/bash$/d' --删除以bash结尾的行

# cat /etc/inittab |sed -e '/^$/d' --删除空行

# head -n 5 /etc/passwd |sed -e '/^[a-z]/d' --删除小写字母开头的行,用[a-z]表示

# head -n 5 /etc/passwd |sed -e '/^[A-Z]/d'--删除大写字母开头的行,用[A-Z]表示

# head -n 5 /etc/passwd |sed -e '/^[a-Z]/d' --删除以字母开头的行,用[a-Z]表示,小写的a到大写的Z

# head -n 5 /etc/passwd |sed -e '/^[[:alpha:]]/d' --也是删除以字母开头的

# head -n 5 /etc/passwd |sed -e '/^[[:digit:]]/d' --删除以数字开头的

# head -n 5 /etc/passwd |sed -e '/^[[:upper:]]/d' --删除以大写字母开头的

# head -n 5 /etc/passwd |sed -e '/^[[:lower:]]/d' --删除以小写字母开头的

# head -n 5 /etc/passwd |sed -e '/^[[:punct:]]/d' --删除以标点符号开头的

# head -n 5 /etc/passwd |sed -e '/^[[:blank:]]/d' --删除以空格开头的

# head -n 5 /etc/passwd |sed -e '/^ /d' --同上

# head -n 5 /etc/passwd |sed -e '/^\ /d' --同上

# cat /etc/inittab |sed -e '/^#/d;/^$/d' --删除/etc/inittab的空行和注释

# cat /etc/samba/smb.conf |sed '/#/d;/^$/d;/^;/d' --删除samba配置文件的注释和空行,注意有几个#号开头的注释不是顶格,所以#只匹配就行

练习:删除vsftpd.conf,smb.conf,main.cf里所有的注释和空行

# sed '/^#/d;/^$/d' /etc/vsftpd/vsftpd.conf

# sed '/^#/d;/^$/d;/^ /d' /etc/postfix/main.cf

# sed '/#/d;/^$/d;/^;/d;/^\t$/d' /etc/samba/smb.conf

3.3 替换用法

sed的语法:

sed '范围 s/老字符/新字符/标记' file

sed '范围 s#老字符#新字符#标记' file

如果不指定范围,默认范围是整个文件。

sed 'y/老字符/新字符/'

实例:

# head -5 /etc/passwd | nl |sed '1,4s/nologin/NOLOGIN/g'

# sed 's#nologin#NOLOGIN#g' /etc/passwd --g是标记,表示全部,也可以使用数字,1,2,3等进行替换,#号只有替换的时候才能用

# sed 's/nologin/NOLOGIN/g' /etc/passwd

# sed '1s/root/--&--/2' /etc/passwd --老字符支持正则表达式,新字符不支持正则表达式,除了"\n\&",这里的"&"表示前面的关键字

# sed '1{s/root/ROOT/;s/bin/BIN/}' /etc/passwd --多次替换使用花括号和分号

# sed 'y/abc/xyz/' file --y也是替换,a->x b->y c->z

# cat /etc/sysconfig/network-scripts/ifcfg-eth0 | sed '/^onboot/c\onboot=yes' --将onboot开头的行替换成onboot=yes,行替换

# cat /etc/sysconfig/network-scripts/ifcfg-eth0 | sed 's/ONBOOT="no"/ONBOOT="yes"/'

# head -5 /etc/passwd |sed -e 's/root/sed/'

# head -5 /etc/passwd |sed -e 's/:/@_@/' --把每一行的第一个匹配的字符替换

# head -5 /etc/passwd |sed -e 's/:/@_@/g' --后面加一个g,代表全替换

# head -5 /etc/passwd |sed -e 's/:/&@_@&/g' --&符号代表前面匹配的字符串

# head -5 /etc/passwd |sed -e '2,4s/:/&@_@&/g' --指定替换2到4行

# head -5 /etc/passwd |sed -e '1,$s/:/&@_@&/g' --替换所有行,默认不加的话就是替换所有行

# head -5 /etc/passwd |sed -e '/^root/,/^adm/s/:/&@_@&/g' --使用正则表达式来表示替换的行范围

# head -5 /etc/passwd |sed -e '/^root/s/:/@_@/g;/^adm/s/:/@_@/g' --替换以root开头的行和替换以adm开头的行

# cat 123.txt

121212

# sed 's/1/3/2' 123.txt --把第2个1替换成3

123212

# head -5 /etc/passwd |sed 's/root/sed/1;s/root/sed/2' --这是把第一个和第三个root改成sed,注意后面是数字2不是3,因为第一个改过,再执行的话,原来的第三个变成第二个

比较awk

去掉第一行第六列的/root

# head -5 /etc/passwd |cat -n |sed '1s/\/root//'

# head -5 /etc/passwd |cat -n |awk -F: 'NR==1 {print $1":"$2":"$3":"$4":"$5"::"$7} NR!=1 {print $0}'

去掉第一行的4到7个字符

# head -5 /etc/passwd |sed '1s/t:x://'

# head -5 /etc/passwd |awk 'NR==1 {print substr($0,1,3)substr($0,8)} NR!=1 {print $0}'

# head -5 /etc/passwd |awk 'NR==1 {print substr($0,1,3)substr($0,8,length($0)-7)} NR!=1 {print $0}

# ls

anaconda-ks.cfg Documents file install.log.syslog Music Pictures Templates

Desktop Downloads install.log Mail nohup.out Public Videos

# ls > /tmp/filename

# sed 's/^/\/root\//' /tmp/filename

3.4 插入i(insert)和追加a(append)

# sed '/^root/i\the first line' file --在root开头行的上面插入一行

# sed '/^root/a\the first line' file --在root开头行的下面插入一行

# cat 1.txt

11111

22222

44444

55555

# sed -i '2a33333' 1.txt --在第2行后加上33333这一行(a代表append)

# cat 1.txt

11111

22222

33333

44444

55555

# sed -i '1i00000' 1.txt --在第1行插入00000这一行(i代表insert)

# cat 1.txt

00000

11111

22222

33333

44444

55555

# sed -i '/^4/accccc' 1.txt --把数字一样可以完全换成正则表达式(这里表示在4开头的行的后一行加上ccccc这一行

# cat 1.txt

00000

11111

22222

33333

44444

ccccc

55555

# sed -e '1i00000' -e '2a33333' 1.txt --2此插入数据,都是针对源文件来操作

3.5 修改之后保存

# sed -i '/^root/a\the first line' file --修改源文件的操作要谨慎

3.6 其他功能(了解)

3.6.1 从文件读入:r命令(read)

# cat file

root:x:0:0:root:/root:/bin/bash

bin:x:1:1:bin:/bin:/sbin/nologin

daemon:x:2:2:daemon:/sbin:/sbin/nologin

adm:x:3:4:adm:/var/adm:/sbin/nologin

lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

sync:x:5:0:sync:/sbin:/bin/sync

shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

# cat test

DEVICE="eth1"

BOOTPROTO="dhcp"

NM_CONTROLLED="no"

ONBOOT="yes"

TYPE="Ethernet"

# sed '/shutdown/r test' file --从文件读入

root:x:0:0:root:/root:/bin/bash

bin:x:1:1:bin:/bin:/sbin/nologin

daemon:x:2:2:daemon:/sbin:/sbin/nologin

adm:x:3:4:adm:/var/adm:/sbin/nologin

lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

sync:x:5:0:sync:/sbin:/bin/sync

shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

DEVICE="eth1"

BOOTPROTO="dhcp"

NM_CONTROLLED="no"

ONBOOT="yes"

TYPE="Ethernet"

3.6.2 写入文件:w命令(write)

# sed -n '/root/w test' file

# cat test

root:x:0:0:root:/root:/bin/bash

3.6.3 下一个:n命令(next)

n:以覆盖的方式读去下一行。

# sed '/root/{n;s/bin/BIN/g;}' file

root:x:0:0:root:/root:/bin/bash

BIN:x:1:1:BIN:/BIN:/sBIN/nologin

daemon:x:2:2:daemon:/sbin:/sbin/nologin

adm:x:3:4:adm:/var/adm:/sbin/nologin

lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

sync:x:5:0:sync:/sbin:/bin/sync

shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

# sed -n 'n;p' file

bin:x:1:1:bin:/bin:/sbin/nologin

adm:x:3:4:adm:/var/adm:/sbin/nologin

sync:x:5:0:sync:/sbin:/bin/sync

3.6.4 退出:q命令(quit)

# sed '3q' file

root:x:0:0:root:/root:/bin/bash

bin:x:1:1:bin:/bin:/sbin/nologin

daemon:x:2:2:daemon:/sbin:/sbin/nologin

3.6.5 行号

# sed -n '/root/{!d;=}' file --等号打印行号

# sed -n '/root/{p;=}' file --等号打印行号

4.使用组或者域进行打印的定位

\(\)是将\( 和 \) 之间的字符串(这个字符串可以用正则表达式)定义为组,并且将匹配这个表达式的保存到一个区域(一个正则表达式最多可以保存9个),它们使用\1到\9来表示

或者使用扩展模式() 直接把括号内的字符串定义为组

例1:把hehe,haha.heihei变成haha,heihei.hehe

用cut和echo的方法

a1=`echo "hehe,haha.heihei" |cut -d"," -f1`

a2=`echo "hehe,haha.heihei" |cut -d"." -f1 |cut -d"," -f2`

a3=`echo "hehe,haha.heihei" |cut -d"." -f2`

echo "$a2,$a3.$a1"

用awk的方法

echo "hehe,haha.heihei" |awk -F[,.]* '{print $2","$3"."$1}'

echo "hehe,haha.heihei" |awk '{print substr($0,6,4)substr($0,5,1)substr($0,11)substr($0,10,1)substr($0,1,4)}'

用sed的方法

echo "hehe,haha.heihei" |sed 's/\(.*\),\(.*\)\.\(.*\)/\2,\3.\1/'

--这是老写法,所有的()都要加\转义符.

echo "hehe,haha.heihei" |sed -r 's/(.*),(.*)\.(.*)/\2,\3.\1/'

--扩展写法,要加-r参数,分隔符的.号还是要转义

echo "hehe,haha.heihei" |sed -r 's/(....)(.)(....)(.)(......)/\3\2\5\4\1/'

echo "hehe,haha.heihei" |sed -r 's/(....)(.)(....)(.)(.{6})/\3\2\5\4\1/'

--(.{6})这是表示6个点,也就是6个字符一个域

查找/etc/passwd文件里的第345个字符

cat /etc/passwd |awk '{printf ("%s",$0)}' |cut -c345

cat /etc/passwd |awk '{printf ("%s",$0)}' |awk '{print substr($0,345,1)}'

cat /etc/passwd |awk '{printf ("%s",$0)}' |sed -r 's/(.{344})(.)(.*)/\2\n/'

cat /etc/passwd |xargs |cut -c345 --但这种做法相对于printf来说,它会把每行的换行符也算一个字符

# cat /etc/passwd | xargs|tr -d " " | cut -c345

例2:打印出下面大小里的前两位(也就是82)

# ll shell05.txt

-rw-r--r-- 1 root root 8263 Jul 31 11:45 shell05.txt

# ll shell05.txt |cut -d" " -f5|cut -c1-2

82

# ll shell05.txt |awk '{print substr($5,1,2)}'

82

ll shell05.txt |awk '{print substr($0,index($0,"82"),2)}'

82

# ll shell05.txt |sed -r 's/(.......................)(..)(.*)/\2/'

82

二. expect脚本

1. expect简介

expect是一个用来处理交互的命令。借助Expect,我们可以将交互过程写在一个脚本上,使之自动化完成。

expect(自动应答) 基于TCL(Tool Command Language)语言演变而来

expect中最关键的三个命令是:

send:用于向进程发送字符串

expect:从进程接收字符串

spawn:启动新的进程(执行一条命令)

2. 安装expect

# yum install expect -y

# rpm -qi expect

Summary : A program-script interaction and testing utility

Description :

Expect is a tcl application for automating and testing

interactive applications such as telnet, ftp, passwd, fsck,

rlogin, tip, etc. Expect makes it easy for a script to

control another program and interact with it.

This package contains expect and some scripts that use it.

任何有交互性的操作,都可以用expect来做

3. expect使用详解

#!/bin/bash

expect <<EOF > /dev/null 2>&1

spawn passwd a --执行passwd a这个命令

expect "rd:" --当停在rd:结尾这个标识符时

send "456\r" --我就把456传给它

expect "rd:" --当再次停在rd:结尾这个标识符时

send "456\r" --我就再次把456传给它

expect eof --表示expect结束

EOF

# sh 1.expect

练习:下载192.168.199.10的ftp上的isolinux目录到/test/目录

#!/bin/bash

expect << EOF > /dev/null 2>&1

spawn lftp 192.168.199.10

expect ":~>"

send "mirror isolinux /test/"

expect ":/>"

send "quit\r"

expect eof

EOF

远程ssh

#!/bin/bash

sed -i '/^'$1'/d' /root/.ssh/known_hosts

expect << EOF > /dev/null 2>&1

spawn ssh $1

expect "no)?"

send "yes\r"

expect "password:"

send "123456\r"

expect "# "

send "touch /root/Desktop/123\n"

send "exit\n"

expect eof

EOF

--关于上面跳过yes的问题,可以加下面的参数来做

ssh 192.168.1.59 -o StrictHostKeyChecking=no

#!/usr/bin/expect

set host [lindex $argv 0]

set user [lindex $argv 1]

set passwd [lindex $argv 2]

spawn ssh -o StrictHostKeyChecking=no $user@$host

expect "password:"

send "$passwd\r"

expect "]" --如果用户有时是root,以]#为提示符,有时是普通用户,以]$为提示符,那么就直接expect "]"就可以了

send "touch /tmp/$user\n" --\n和\r都行,因为要测试不同的用户,所以要对用户都有写权限,这里就用/tmp目录来测试

send "exit\n"

expect eof --rhel6下测试的是一定要加这个

# sh 5.expect 192.168.1.59 root 123456 --这样执行是错误的。因为sh命令就是直接调用bash去解释,不管你脚本开头定义的#!/usr/bin/expect

# chmod 755 5.expect

# ./5.expect 192.168.1.59 root 123456 --正确执行方法

# expect 5.expect 192.168.1.59 root 123456 --或者直接指定由expect命令来执行

综合练习:

假设管理的机器有N台,密码也各不相同(没有ssh等效性),现在需要在每个机器上都创建一个文件

# cat ip_user_passwd.txt --这个文件里包含你所有管理机器的IP,用户及其对应的密码

10.1.1.63 root oracle

10.1.1.77 root 1234

10.1.1.73 user1 123456

10.1.1.85 root 54321

......

# cat 6.expect

#!/bin/bash

cat ip_user_passwd.txt |while read ip user password

do

sed -i '/^'$ip'/d' /root/.ssh/known_hosts

expect <<EOF &> /dev/null

spawn ssh $ip -l $user

expect ")?"

send "yes\r"

expect "rd:"

send "$password\n"

expect "]#"

send "touch /tmp/123\n" --这里可以修改你每次要在这些机器上做的命令

send "exit\n"

expect eof

EOF

done

三. 脚本加密

1.gzexe --压缩工具

# gzexe 1.sh

# gzexe -d 1.sh

2.shc

官方下载地址:http://www.datsi.fi.upm.es/~frosal/sources/

wget http://www.datsi.fi.upm.es/~frosal/sources/shc-3.8.7.tgz

# tar xvf shc-3.8.7.tgz -C /usr/src/

# cd /usr/src/shc-3.8.7/

# make

# make install

# shc -f 1.sh --生成可执行文件1.sh.x和1.sh.x.c

# ./1.sh.x

经过测试,rhel6.x不能执行1.sh.x,可以更换其他平台测试。

3. gpg

采用密钥签名技术保护文件内容,只有经过认证的用户才能访问数据

加密

# gpg -c1.txt --输入密码后,会生成1.txt.gpg文件

解密

# gpg 1.txt.gpg --弹出对话框,输入密码后即可解密

4. base64

将ASCII字符转换成以64为基数的形式来用ASCII字符串描述二进制数据

编码为Base64格式

# base64 1.txt > 2.txt

解密Base64格式

# base64 -d 2.txt > 3.txt

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表