shell脚本-字符串操作,扩展应用,正则表达式

字符串处理

  1. 字符串截取与切割
    • 三种方法
      • ${变量名:起始位置 : 长度}
      • expr substr “$变量名字” 起始位置 长度
      • echo $变量名 | cut -b 起始为位置-结束位置
#截取第一种方法
[root@room13pc37 ~]# a=abcdef
[root@room13pc37 ~]# echo $a
abcdef
[root@room13pc37 ~]# echo ${a:2:2}		#注意:截取的位置是从0(下标)开始计数的
cd
[root@room13pc37 ~]# echo ${a: :2}		#中间省略就表示:从第一0位开始截取	可以省略0
cd
[root@room13pc37 ~]# echo ${#a}			#  ${#a }中#的作用是:统计字符串的数量,(注意:#是在这里是单独使用的)
6
#方法2
[root@room13pc37 ~]# a=abcdef
[root@room13pc37 ~]# echo $a
abcdef[root@room13pc37 ~]# expr substr "$a" 2 5		#注意区分和方法1的不同	。同时它的位置是从1(下标)开始数的
#方法3
[root@room13pc37 ~]# echo $a | cut -b 3-5		#与方法2一样位置是从1开始计数, 但是 “5” 表示 截取到那里。==> 截取3到5之间的字符。(相对灵活)
cde
[root@room13pc37 ~]# echo $a | cut -b 3,5	# "," 表示:只截取 3,5 这两个位置的字符
ce
[root@room13pc37 ~]# echo $a | cut -b -5	#表示截取:1 -5 之间的字符,1可以省略
abcde
[root@room13pc37 ~]# echo $a | cut -b 1-5	#同上
abcde
[root@room13pc37 ~]# echo $a | cut -b 5	#表示只要第 5 位的字符
e
  • **例子1 **编写一个随机获取字符的脚本
#!/binb/bash
#随机生成一个字符
a=abcdefghijklnmopqrstuvwxyzABCDEFGHIJKLNMOPQRSTUVWXYZ1234567890	#定义变量,一共62字符
for i in {1..8}
do
        x=$[RANDOM%62]		#随机生成,范围是0~61 
        pass=${a:x:1}			#截取1个字符给pass
        pass1=$pass1$pass		#每次随机生成的数字,赋值给pass
done
echo $pass1						#显示出来
--------------------------------------
#结果
[root@room13pc37 shell_test]# bash Random_code_for
0lkK6ppG

  1. 字符串替换
    • 只替换第一个匹配结果: ${变量名/old/new}
    • 替换全部匹配结果: ${变量名//old/new}
[root@room13pc37 shell_test]# echo ${b/d/*}		#只替换一个
1*safsafsadfs33515465fsdfads
[root@room13pc37 shell_test]# echo ${b//d/*}	#全部替换
1*safsafsa*fs33515465fs*fa*s
[root@room13pc37 shell_test]# echo ${b//d/}		#替换为空,相当delete
1safsafsafs33515465fsfas

  1. 字符串掐头去为尾
    • 从左向右,最短匹配删除,${变量名#*关键词}
    • 从左向右,最长匹配删除,${变量名##*关键词}
    • 从右向左,最短匹配删除,${变量名%*关键词}
    • 从右向左,最长匹配删除,${变量名%%*关键词}
#左边删除
[root@room13pc37 shell_test]# a=`head -1 /etc/passwd`
[root@room13pc37 shell_test]# echo $a
root:x:0:0:root:/root:/bin/bash
[root@room13pc37 shell_test]# echo ${a#root}		#指定删除(掐头)的内容
:x:0:0:root:/root:/bin/bash
[root@room13pc37 shell_test]# echo ${a#root:}
x:0:0:root:/root:/bin/bash
[root@room13pc37 shell_test]# echo ${a#*:}			#利用*来匹配掐头的内容
x:0:0:root:/root:/bin/bash
[root@room13pc37 shell_test]# echo ${a##*:}			#从左往右边开始其逐个匹配桥头
/bin/bash
[root@room13pc37 shell_test]# 
--------------------------------------------
#从右往左删除	= 去尾
[root@room13pc37 shell_test]# echo $a
root:x:0:0:root:/root:/bin/bash
[root@room13pc37 shell_test]# echo ${a%/bin*}		#匹配去尾的内容
root:x:0:0:root:/root:
[root@room13pc37 shell_test]# echo ${a%/bi*}
root:x:0:0:root:/root:
[root@room13pc37 shell_test]# echo ${a%/:*}
root:x:0:0:root:/root:/bin/bash
[root@room13pc37 shell_test]# echo ${a%%:*}		#从右往左开始匹配去尾的对象
root
[root@room13pc37 shell_test]# 
  • 例子2 只保留 root: x :0:0:root:/root:/bin/bash ===> 中间的“root”
[root@room13pc37 shell_test]# echo $a
root:x:0:0:root:/root:/bin/bas
[root@room13pc37 shell_test]# b=${a%:*}	#可以用一个变量来存去尾后的值
[root@room13pc37 shell_test]# echo $b	
root:x:0:0:root:/root
[root@room13pc37 shell_test]# echo ${b##*:/}	#在把掐头去掉变量 B  剩下的值
root
  • 例子3 批量修改文件的后缀 如:把 ”.txt“ 文件修改为 " .doc"
#!/bin/bash
#利用字符串删除命令,批量修改文件名字
[root@room13pc37 test_fileName]# touch {1..20}.txt
[root@room13pc37 test_fileName]# ls
10.txt  12.txt  14.txt  ....
for i in `ls *.txt`
do
        mv $i ${i%.*}.doc		#我这里使用的是相对路径,大家可以使用绝对路径,更加精准一点;	去尾的部分是:  .txt;
        [ $? -eq 0 ] && echo "$i 修改成功" || echo "$i修改失败"		#判断是否修修改成功
done
#结果
[root@room13pc37 test_fileName]# ls
10.doc  13.doc  16.doc  19.doc ....
---------------------
#这个脚本还是有可优化的地方,我们可以把 把位置变量  $1 替换.txt   $2 替换 .doc 
#这样我们可以修改任意的文件名可扩展名阿

字符串备用值设置(初值)。

  • 取值: ${var:-word}
    - 若变量var已经存在且非NULL, 则返回$var的值
    - 否则返回子串"word",变量var值不变

  • 例子4 创建用户,并设置初始化密码。默认123456

#!/bin/bash
#创建用户,并设置密码,不设置密码,默认123456
read -p "请输入用户名" u
useradd $u
read -p "请输入密码" p
echo ${p:-123456} | passwd --stdin $u                                                                                                                    
[root@room13pc37 test_fileName]# bash default_code
请输入用户名alal
请输入密码12345
更改用户 alal 的密码 。
passwd:所有的身份验证令牌已经成功更新。
  • 例子5 从键盘读入一个正整数x,求从1到x的和;当用户未输入值(直接回车)时.为了避免执行出错,应为x赋初值1
#!/bin/bash
#用来从键盘读入一个正整数x,求从1到x的和;当用户未输入值(直接回车)时,为了避免执行出错,应为x赋初值1 
sum=0
read -p "please input a num: " num
for i in `seq ${num:-1}`		#设置默认值
do
         sum=$[sum + i ]		#求和
done
echo $sum

测试结果:

[root@room13pc37 test_fileName]# bash sum_x
please input a num: 10
55
[root@room13pc37 test_fileName]# bash sum_x
please input a num:         
1

shell扩展 expect预期交互

  • 基于TCL编写的自动交互式程序
    • 可以用在shell脚本中,为交互式过程自动输送预先主准备的文本或者指令,无需人工干预
    • 触发的依据式预期出现的特性提示文本
      1.安装expect工具

    我所使用的系统式红帽子 7.4

[root@room13pc37 test_fileName]#yum -y install expect
.....
[root@room13pc37 test_fileName]#which expect		#确定expect路径
/usr/bin/expect
  • 例子6 expect可以为交互式过程(比如FTP、SSH等登录过程)自动输送预先准备的文本或指令,而无需人工干预。触发的依据是预期会出现的特征提示文本
#发邮件的几种方式
[root@room13pc37 test_fileName]# echo "test mail" | mail -s test root	#管道
[root@room13pc37 test_fileName]# mail -s test root < /etc/passwd	#重定向
[root@room13pc37 test_fileName]# mail -s test root << EOF	#expect
test mail
hell world
EOF
  • 例子7 编写脚本,实现免交互登录
  • 任务需求及思路分析

在SSH登录过程中,如果是第一次连接到该目标主机,则首先会被要求接受密钥,然后才提示输入密码:
注意:不要照抄这里的IP地址,需要根据自己的实际IP填写!!!

# ssh [email protected]                              //连接目标主机
The authenticity of host '192.168.4.5 (192.168.4.5)' can't be established.
RSA key fingerprint is 58:a0:d6:00:c7:f1:34:5d:6c:6d:70:ce:e0:20:f8:f3.
Are you sure you want to continue connecting (yes/no)? yes          //接受密钥
Warning: Permanently added '192.168.4.5' (RSA) to the list of known hosts.
[email protected]'s password:                                   //验证密码
Last login: Thu May  7 22:05:44 2015 from 192.168.4.5
[root@room13pc37 test_fileName]# exit                                             //返回客户端
logout
Connection to 192.168.4.5 closed.
  • 如果SSH登录并不是第一次,则接受密钥的环节就没有了,而是直接进入验证密码的过程:

注意:不要照抄这里的IP地址,需要根据自己的实际IP填写!!!

[root@room13pc37 test_fileName]# ssh [email protected]                              //连接目标主机
[email protected]'s password:                                   //验证密码
Last login: Mon May 11 12:02:39 2015 from 192.168.4.5
[root@room13pc37 test_fileName]# exit  
//返回客户端
logout
Connection to 192.168.4.5 closed.

*:不要照抄脚本里的IP地址与密码,需要根据自己的实际情况填写!!!

[root@room13pc37 test_fileName]# vim  expect_ssh.sh 
#!/bin/bash
expect << EOF
spawn ssh 192.168.4.5                               #//创建交互式进程
expect "password:" { send "123456\r" }              #//自动发送密码
expect "#"          { send "touch /tmp.txt\r" }     #//发送命令
expect "#"          { send "exit\r" }
EOF
[root@room13pc37 test_fileName]# chmod  +x  expect_ssh.sh 

2)根据实现思路编写脚本文件

正则表达式概述

在这里插入图片描述

  • Regular Express
    • 使用 “一串符号”,来描述有共同属性的数据’
  • egrep 过滤工具 (可以使用扩展的正则表达式的规则)
    • 文本处理顺序
      • 以为行单位,逐行进行处理
      • 默认只输出与表达式相匹配的文本行
    • 基本用法
      • 格式1: egrep [选项] ‘正则表达式’ 文件……
      • 格式2: 前置命令 | egrep [选项] ‘正则表达式

    等同于: grep -E :表示允许使用扩展的正则表达式

    • 常用命令选项
      • -i : 忽略字母的大小写
      • -v :条件取反
      • -c :统计匹配的行数
      • -q : 静默,无任何输出,一般用于检测
      • -n : 显示出匹配结果所在的行号
      • –color : 标红显示匹配子串
正则符号 描述
$ 匹配行首
[] 匹配行尾
[^] 对集合取反
. 匹配任意单个字符
* 匹配前一个字符任意次数
\{n,m\} 匹配前一个字符n到 名次
{n\} 匹配前一个字符n次
\{n,\} 匹配前一个字符n次以上
\{\} 保留

扩展正则列表

正则符号 描述
+ 最少匹配一次
最多匹配一次
{n,m} 匹配n到m次
() 组合为整体,保留
\b 单词边界
  • 例子8 正则表达式示例
#典型的应用场合:grep、egrep检索文本行grep命令不带-E选项时,支持基本正则匹配模式。比如“word”关键词检索、“^word”匹配以word开头的行、“word$”匹配以word结尾的行……等等。
[root@room13pc37 test_fileName]# grep '^r' /etc/passwd		#输出以“r”开头的用户记录:
[root@room13pc37 test_fileName]# grep 'localhost$' /etc/hosts	#输出以“localhost”结尾的行
	
#若希望在grep检索式同时组合多个条件,比如输出以“root”或者以“daemon”开头的行:
[root@room13pc37 test_fileName]# grep '^root|^daemon' /etc/passwd          //搜索无结果
[root@room13pc37 test_fileName]# grep 'localhost$' /etc/hosts		#而若若使用grep -E或egrep命令,可支持扩展正则匹配模式,能够自动识别 |、{} 等扩展正则表达式中的特殊字符,用起来更加方便,比如:

#而若若使用grep -E或egrep命令,可支持扩展正则匹配模式,能够自动识别 |、{} 等扩展正则表达式中的特殊字符,用起来更加方便,比如:
[root@room13pc37 test_fileName]# grep -E '^(root|daemon)' /etc/passwd

#grep、egrep命令的-q选项
#选项 -q 表示 quiet(静默)的意思,结合此选项可以只做检索而并不输出,通常在脚本内用来识别查找的目标是否存在,通过返回状态 $? 来判断,这样可以忽略无关的文本信息,简化脚本输出。比如,检查/etc/hosts文件内是否存在192.168.4.4的映射记录,如果存在则显示“YES”,否则输出“NO”,一般会执行:
[root@room13pc37 test_fileName]# grep '^192.168.4.4' /etc/hosts && echo "YES" || echo "NO"
[root@room13pc37 test_fileName]# grep -q '^192.168.4.4' /etc/hosts && echo "YES" || echo "NO"

# 基本元字符 ^、$ —— 匹配行首、行尾
[root@room13pc37 test_fileName]# egrep '^#' /etc/inittab	#输出注释的配置行(以#开头的行)

#使用 -c 选项可输出匹配行数,这与通过管道再 wc -l的效果是相同的,但是写法更简便。比如,统计使用“/bin/bash”作为登录Shell的正常用户个数,可执行:
[root@room13pc37 test_fileName]# egrep -c '/bin/bash$' /etc/passwd

基本元字符 +、?、* —— 目标出现的次数
[root@room13pc37 test_fileName]# egrep '.' /etc/rc.local #基本元字符 . —— 匹配任意单个字符
[root@room13pc37 test_fileName]# egrep 'f+' /etc/rc.local	#输出包括 f、ff、ff、……的行,即“f”至少出现一次:
[root@room13pc37 test_fileName]# egrep 'init(ial)?' /etc/rc.local	#输出包括init、initial的行,即末尾的“ial”最多出现一次(可能没有):
		
--------------------------------------------------
[root@room13pc37 test_fileName]# vim brace.txt			#先准备一个素材文件
ab def ghi abdr
dedef abab ghighi
abcab CD-ROM
TARENA IT GROUP
cdcd ababab
Hello abababab World
#元字符 {} —— 限定出现的次数范围
[root@room13pc37 test_fileName]# egrep '(ab){3}' brace.txt	#输出包括ababab的行,即“ab”连续出现3次:
[root@room13pc37 test_fileName]# egrep '(ab){2,4}' brace.txt	#输出包括abab、ababab、abababab的行,即“ab”连续出现2~4次:
[root@room13pc37 test_fileName]# egrep '(ab){3,}' brace.txt	#输出包括ababab、abababab、……的行,即“ab”最少连续出现3次:
[root@room13pc37 test_fileName]# egrep '[A-Z]' brace.txt		#输出包括大写字母的行,使用[A-Z]匹配连续范围:
[root@room13pc37 test_fileName]# egrep -i 'eth|network|bluetooth' /var/log/dmesg		#多个条件的组合通过dmesg启动日志查看蓝牙设备、网卡设备相关的信息:

猜你喜欢

转载自blog.csdn.net/REVE_HOH/article/details/89202727