-- vi vim emacs --可以不用鼠标操作的编辑器 gedit 记事本 word --一般会需要使用鼠标操作的编辑器 sed 流编辑器 --用命令流直接操作的编辑器(都不用打开文件) sed - stream editor for filtering and trans-forming text 编辑器的主要功能一般有: 删除或保留 增加 修改(替换) 删除(以行为单位) head -n 5 /etc/passwd |cat -n |sed '2d' --指定删除第二行 head -n 5 /etc/passwd |cat -n |sed '2,3d' --删除第二行到第三行,中间为逗号,表示范围 head -n 5 /etc/passwd |cat -n |sed '1d;5d' --删除第一行和第五行,中间为分号,表示单独的操作 head -n 5 /etc/passwd |cat -n |sed '1d;5d;3d' head -n 5 /etc/passwd |cat -n |sed '1,3d;5d' head -5 /etc/passwd |cat -n |sed -e '2d;4d' -e '1d' -- e参数是把不同的多种操作可以衔接起来 head -5 /etc/passwd |sed '/daemon/d' 练习:把上面的使用awk来实现,做对比 head -n 5 /etc/passwd |cat -n |awk 'NR==2 {print $0}' --只留下第二行,其它都删除 head -5 /etc/passwd |awk 'NR!=3 {print $0}' --删除第三行 head -5 /etc/passwd |awk '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的空行和注释 练习:sed -i 删除vsftpd.conf,smb.conf,main.cf里所有的注释和空行 # sed -i '/^#/d;/^$/d' /etc/vsftpd/vsftpd.conf # sed -i '/^#/d;/^$/d;/^ /d' /etc/postfix/main.cf # sed -i '/#/d;/^;/d;/^$/d;/^\t$/d' /etc/samba/smb.conf ----------------------------------------------------------- 重装samba,我这里使用yum remove samba*删除了23个软件包 再使用yum install samba-*安装只安装回5个,另外18个建议也装回来 使用下面的命令解决 # cat /var/log/yum.log |sed -n '/Nov 14.*Erased/p' |awk '{print $NF}' |xargs yum install -y ----------------------------------------------------------- 比如网上要查找一个rpm包 常见的网址为 rpm包: centos 163源 epel源 fedorapeople www.rpmfind.net http://rpm.pbone.net 源码: 各软件官网 www.sourceforge.com -------------------------------------------------------------- 打印/保留(删除的反义) head -5 /etc/passwd |sed -e '/root/p' --匹配root的行打印出来,但发现/etc/passwd的前五行也打印出来了 head -5 /etc/passwd |sed -n -e '/root/p' --去除常规打印的信息,只打印匹配的行,要多加一个-n的参数,注意:-n不能加在-e之后,用-ne也可以,但用-en不行 head -5 /etc/passwd |sed -ne '/^root/p' head -5 /etc/passwd |sed -ne '/nologin$/p' cat /etc/inittab |sed -ne '/^$/p' head -5 /etc/passwd |sed -ne '1,4p' head -5 /etc/passwd |sed -ne '1p;4p' 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' --打印非空格开头的行 --下面三条都是把有Accepted关键字的行打印出来 awk '$0~"Accepted" {print $0}' /var/log/ssh.log sed -n '/Accepted/p' /var/log/ssh.log cat /var/log/ssh.log | grep Accepted 比较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}' ================================================================= 增加 # 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 ================================================================ 修改 替换 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 |sed -r '1s/(...)(....)(.*)/\1\3/' 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} =========================================== 练习: 写一个简单初始化系统的脚本 1,自动修改主机名三步(也就是说你获取IP为10.1.1.35,则主机名改成server35.cluster.com) 2,自动配置可以使用的yum 3,自动安装配置vsftp,不允许匿名用户登录,所有普通用户都在笼环境里 anonymous_enable=NO --改为NO chroot_local_user=YES --加上这一句 第一步:配置yum客户端 第二步:使用yum安装所有相关的rpm包,如果后面要用源码包,那么你在这一步就把所有的依赖包都yum install安装 第三步:有可能会用到安装目录的指定,和目录大小的判断 第四步:按照需求来修改配置文件.所有的配置都可以用sed来进行修改;但如果修改的选项特别多,还有一个傻瓜式的方法可能更方便;就是直接准备好一个修改好的文件,直接拷过去覆盖就可以了 第五步:启动服务,可能要chkconfig on iptail=`ifconfig eth0 |grep Bcast|awk -F"[. ]*" '{print $6}'` hostname server$iptail.cluster.com echo "10.1.1.$iptail server$iptail.cluster.com" >> /etc/hosts sed -i '/HOSTNAME/s/localhost.localdomain/server$iptail.cluster.com/' /etc/sysconfig/network ping -c 1 10.1.1.35 >/dev/null 2>&1 if [ $? -ne 0 ];then echo "你的网络不通,请先检查网络再继续安装 exit 1 else echo "正在安装中,请耐心等待......" fi cat > /etc/yum.repos.d/rhel-source.repo << EOF [server] name=server baseurl=ftp://10.1.1.35 enabled=1 gpgcheck=0 EOF yum install vsftpd -y &> /dev/null sed -i '/^anonymous_enable/s/YES/NO/' /etc/vsftpd/vsftpd.conf echo "chroot_local_user=YES" >> /etc/vsftpd/vsftpd.conf service vsftpd start &> /dev/null chkconfig vsftpd on echo "安装完成" ====================================================================== 使用组或者域进行打印的定位 \(\)是将\( 和 \) 之间的字符串(这个字符串可以用正则表达式)定义为组,并且将匹配这个表达式的保存到一个区域(一个正则表达式最多可以保存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个字符(换行符不计算为1个字符) 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/' 打印出下面大小里的前两位(也就是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 打印整行,但是把82和63互换 # ll shell05.txt -rw-r--r-- 1 root root 8263 Jul 31 11:45 shell05.txt # echo -e "$(ll shell05.txt |cut -c1-23)$(ll shell05.txt |cut -c26-27)$(ll shell05.txt |cut -c24-25)$(ll shell05.txt |cut -c28-)" # ll shell05.txt |awk '{print $1,$2,$3,$4,substr($5,3,2)substr($5,1,2),$6,$7,$8,$9}' -rw-r--r-- 1 root root 6382 Jul 31 11:45 shell05.txt # ll shell05.txt |sed -r 's/(.......................)(..)(..)(.*)/\1\3\2\4/' -rw-r--r-- 1 root root 6382 Jul 31 11:45 shell05.txt #ll shell05.txt |sed -r 's/(.{23})(..)(..)(.*)/\1\3\2\4/' -rw-r--r-- 1 root root 6382 Jul 31 11:45 shell05.txt 删除每行的第一个字符(都可以以/etc/passwd文件的前五行为例来做测试) head -5 /etc/passwd |cut -c2- head -5 /etc/passwd |awk '{print substr($0,2)}' head -5 /etc/passwd |awk -F"^." '{print $2}' head -5 /etc/passwd |awk '{gsub(/^./,"");print $0}' head -5 /etc/passwd |sed -r 's/(.)(.*)/\2/' head -5 /etc/passwd |sed -r 's/.//1' head -5 /etc/passwd |sed -r 's/^.//' 删除每行的第二个字符 head -5 /etc/passwd |cut -c1,3- head -5 /etc/passwd |awk '{print substr($0,1,1)substr($0,3)}' head -5 /etc/passwd |sed -r 's/(.)(.)(.*)/\1\3/' head -5 /etc/passwd |sed -r 's/.//2' 删除每行的第九个字符 head -5 /etc/passwd |cut -c1-8,10- head -5 /etc/passwd |awk '{print substr($0,1,8)substr($0,10)}' head -5 /etc/passwd |sed -r 's/(.{8})(.)(.*)/\1\3/' head -5 /etc/passwd |sed -r 's/.//9' 删除倒数第5个字符 head -5 /etc/passwd |rev |cut -c1-4,6- |rev head -5 /etc/passwd |awk '{print substr($0,1,length($0)-5)substr($0,length($0)-3)}' head -5 /etc/passwd |sed -r 's/(.*)(.)(....)/\1\3/' 把每行的第5个字符和第8个字符互换,并删除第10个字符 head -5 /etc/passwd | awk '{print substr($0,1,4)substr($0,8,1)substr($0,6,2)substr($0,5,1)substr($0,9,1)substr($0,11)}' head -5 /etc/passwd | sed -r 's/(....)(.)(..)(.)(.)(.)(.*)/\1\4\3\2\5\7/' 删除/etc/passwd里的注释列(第五列)的内容 head -5 /etc/passwd |cut -d":" -f1,2,3,4,6,7 --错误,打印出来后会少了一个:分隔符 head -5 /etc/passwd |awk -F: '{print $1":"$2":"$3":"$4"::"$6":"$7}' head -5 /etc/passwd |sed -r 's/(.*):(.*):(.*):(.*):(.*):(.*):(.*)/\1:\2:\3:\4::\6:\7/' 正则表达式补充: a+代表1个或多个a [a-z]+代表多个小写字母 [A-Z]+代表多个大写字母 [a-Z]+代表多个字母 cat 1.txt I'm a teacher You're a student He's old-fashioned. 删除每行的第一个单词 # cat 1.txt |sed -r 's/([a-Z]+)(.*)/\2/' 删除每行的第二个单词 # cat 1.txt |sed -r 's/([a-Z]+)([^a-Z]+)([a-Z]+)(.*)/\1\2\4/' 删除每行的最后一个单词 # cat 1.txt |sed -r 's/(.*)([^a-Z]+)([a-Z]+)/\1\2/' 删除每行的倒数第二个单词 # cat 1.txt |sed -r 's/(.*)([^a-Z]+)([a-Z]+)([^a-Z]+)([a-Z]+)/\1\2\4\5/' ======================================================================== 对apache的日志进行处理 例1 找自己的apache的访问日志access.log(httpd日志)日志文件 处理前格式为: 10.1.1.183 - - [02/Apr/2011:15:36:54 +0800] "GET /shell05/shell05.txt HTTP/1.1" 200 6305 "http://10.1.1.35/shell05/" "Mozilla/5.0 (X11; U; Linux i686; zh-CN; rv:1.9.0.12) Gecko/2009070811 Red Hat/3.0.12-1.el5_3 Firefox/3.0.12" 处理后格式为: 第一种: 时间 访问ip 访问文件 2011-apr-02 15:36:54 10.1.1.183 shell05.txt 第二种: 时间 IP 文件 访问文件全路径 2011-apr-02 15:36:54 10.1.1.183 http://10.1.1.35/shell05/shell05.txt 课后了解开源web日志分析工具 awstats webalizer 例2: 针对access2_log(squid日志)进行整理,要求整理后的格式为 --注意此文件里的格式的第一列是表示的从1970-01-01的0点到现在的秒数 --date +%s --date='2008-09-26 23:07:42' 1222441662 时间 访问ip 访问文件 2008-09-26 23:07:40 192.168.20.171 http://www.google.com/ --提示:man awk查找strftime head access2_log |awk '$7 ~ "http" {print strftime ("%Y-%m-%d %H:%M:%S",$1),$3,$7}' =============================================================== 你想对远程机器进行脚本操作,需要ssh上去,你是知道密码的,但是按以前的方法,没办法传密码 有两种方法解决: 1,ssh密钥,等效性 2,expect expect 自动应答 TCL(Tool Command Language)语言 yum install expect -y 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来做 例1,使用expect修改用户密码 #!/bin/bash expect < /dev/null 2>&1 spawn passwd $1 --产生passwd $1这个命令 expect "rd:" --当停在rd:结尾这个标识符时 send "456\r" --我就把456传给它 expect "rd:" --当再次停在rd:结尾这个标识符时 send "456\r" --我就再次把456传给它 expect eof --表示expect结束 EOF # sh 1.expect test --执行方法,因为脚本里写的是$1,所以后面接你要修改密码的用户名 例2,使用expect下载同步ftp共享的文件 # cat 2.expect #!/bin/bash expect <" send "mirror basic/ /notes/\r" send "mirror shell/ /notes/\n" send "quit\n" expect eof EOF # sh 2.expect 例3,使用expect实现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 10.1.1.36 -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 10.1.1.34 root 123456 --这样执行是错误的。因为sh命令就是直接调用bash去解释,不管你脚本开头定义的#!/usr/bin/expect # chmod 755 5.expect # ./5.expect 10.1.1.34 root 123456 --正确执行方法 # expect 5.expect 10.1.1.11 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 < /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 2.shc ==================================== 学习完shell后你应该可以写出下列几大类脚本: 触发型脚本 自动安装型 监控警告型 自动管理型 日志处理型 自动应答型 ==================================================================