字符串处理
- 字符串截取与切割
- 三种方法
- ${变量名:起始位置 : 长度}
- 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
- 字符串替换
- 只替换第一个匹配结果: ${变量名/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
- 字符串掐头去为尾
- 从左向右,最短匹配删除,${变量名#*关键词}
- 从左向右,最长匹配删除,${变量名##*关键词}
- 从右向左,最短匹配删除,${变量名%*关键词}
- 从右向左,最长匹配删除,${变量名%%*关键词}
#左边删除
[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启动日志查看蓝牙设备、网卡设备相关的信息: