shell之字符串操作

在使用脚本的时候,字符串是我们经常用的对象,还经常会用到查找,替换,删减,比较等等操作。本人稍作整理,希望能对新人有所帮助,本人也是新人,(*^__^*) 嘻嘻……


1.判断字符串的属性

  一般用到的也就是  是不是数字,书不是字母等等

// 数字或者数字组合(能够返回结果,即程序退出状态是0,说明属于这种类型,反之不然)
$ i=5;j=9423483247234;
$ echo $i | grep [0-9]*
5
$ echo $j | grep [0-9]*
9423483247234
$ echo $j | grep [0-9]* > /dev/null
0
// 字符组合(小写字母、大写字母、两者的组合)
$ c= "A" ; d= "mynameisyfc" ; e= "whatyourname"
$ echo $c | grep [A-Z]
A
$ echo $d | grep "[a-z]*"
mynameisyfc
$ echo $e | grep "[a-zA-Z]*"
whatyourname
// 字母和数字的组合
$ ic= "432fwfwefeFWEwefwef"
$ echo $ic | grep "[0-9a-zA-Z]*"
432fwfwefeFWEwefwef
// 空格或者Tab键等
$ echo " " | grep " "  
$ echo -e "\t" | grep "[[:space:]]" #[[:space:]]会同时匹配空格和TAB键 
$ echo -e " \t" | grep "[[:space:]]" 
$ echo -e "\t" | grep "<tab>" #<tab>为在键盘上按下TAB键,而不是字符<tab>

// 用grep判断某个字符是否为可打印字符
$ echo "\t\n" | grep "[[:print:]]"
\t\n
$ echo $?
0
$ echo -e "\t\n" | grep "[[:print:]]"
$ echo $?
1
// 用echo的-e选项在屏幕控制字符显示位置、颜色、背景等
$ echo -e "\33[31;40m" #设置前景色为黑色,背景色为红色
$ echo -e "\33[11;29H Hello, World\!" #在屏幕的第 11 行, 29 列开始打印字符串Hello,World!
// 在屏幕的某个位置动态显示当前系统时间
$ while :; do echo -e "\33[11;29H " $(date "+%Y-%m-%d %H:%M:%S" ); sleep 1s;done

2.计算字符串的长度

// 计算某个字符串的长度,即所有字符的个数[这计算方法是五花八门,择其优着而用之]
$ var= "get the length of me"
$ echo ${var}     # 这里等同于$var
get the length of me
$ echo ${ #var}
20
$ expr length "$var"
20
$ echo $var | awk '{printf("%d\n", length($0));}'
20
$ echo -n $var |  wc -c
20


3.字符串数组应用与转换

//1 . bash 提供的数组数据结构,它是以数字为下标的,和C语言从0开始的下标一样
$ var= "get the length of me"
$ var_arr=($var)    #这里把字符串var存放到字符串数组var_arr中了,默认以空格作为分割符
$ echo ${var_arr[0]} ${var_arr[1]} ${var_arr[2]} ${var_arr[3]} ${var_arr[4]}
get the length of me
$ echo ${var_arr[@]}    #这个就是整个字符串所有部分啦,这里可以用*代替@,下同
get the length of me
$ echo ${ #var_arr[@]}    #记得上面求某个字符串的长度么,#操作符,如果想求某个数组元素的字符串长度,那么就把@换成下标吧
5
// 你也可以直接给某个数组元素赋值
$ var_arr[5]= "new_element"
$ echo ${var_arr[5]}
6
$ echo ${var_arr[5]}
new_element
// bash 里头实际上还提供了一种类似于“数组”的功能,即 "for i in 用指定分割符分开的字符串" 的用法
// 即,你可以很方便的获取某个字符串的某个部分
$  for i in $var; do echo -n $i " " ; done ;
get the length of me
 
//2 . awk 里头的数组,注意比较它和 bash 提供的数组的异同
// split 把一行按照空格分割,存放到数组var_arr中,并返回数组的长度。注意:这里的第一个元素下标不是0,而是1
$ echo $var | awk '{printf("%d %s\n", split($0, var_arr, " "), var_arr[1]);}'
5 get
// 实际上,上面的操作很类似 awk 自身的行处理功能: awk 默认把一行按照空格分割为多个域,并可以通过$1,$2,$3...来获取,$0表示整行
// 这里的NF是该行的域的总数,类似于上面数组的长度,它同样提供了一种通过“下标”访问某个字符串的功能
$ echo $var | awk '{printf("%d | %s %s %s %s %s | %s\n", NF, $1, $2, $3, $4, $5, $0);}'
5 | get the length of me | get the length of me
// awk 的“数组”功能何止于此呢,看看它的 for 引用吧,注意,这个和 bash 里头的 for 不太一样,i不是元素本身,而是下标
$ echo $var | awk '{split($0, var_arr, " "); for(i in var_arr) printf("%s ",var_arr);}'
get the length of me
$ echo $var | awk '{split($0, var_arr, " "); for(i in var_arr) printf("%s ",i);}'
1 2 3 4 5

4. 字符串常规操作

字符串操作包括取子串、查询子串、插入子串、删除子串、子串替换、子串比较、子串排序、子串进制转换、子串编码转换等。

4.1 取子串

// 按照位置取子串,比如从什么位置开始,取多少个字符
$ var= "get the length of me"
$ echo ${var:0:3}
get
$ echo ${var:(-2)}   # 方向相反呢
me
$ echo ` expr substr "$var" 5 3` #记得把$var引起来,否则expr会因为空格而解析错误
the
$ echo $var | awk '{printf("%s\n", substr($0, 9, 6))}'
length
 
// 匹配字符求子串
$ echo ${var%% *} #从右边开始计算,删除最左边的空格右边的所有字符
get
$ echo ${var% *} #从右边开始计算,删除第一个空格右边的所有字符
get the length of
$ echo ${var ##* }  #从左边开始计算,删除最右边的空格左边的所有字符
me
$ echo ${var #* }  #从左边开始计算,删除第一个空格左边的所有字符
the length of me
 
$ echo $var | awk '{printf("%s\n", $1);}' # awk把$var按照空格分开为多个变量,依次为$1,$2,$3,$4,$5
get
$ echo $var | awk '{printf("%s\n", $5);}'
me
 
$ echo $var | cut -d " " -f 5  #差点把cut这个小东西忘记啦,用起来和awk类似, -d指定分割符,如同awk用-F指定分割符一样,-f指定“域”,如同awk的$数字。
 
$ echo $var | sed 's/ [a-z]*//g'  #删除所有 空格+字母串 的字符串,所以get后面的全部被删除了
get
$ echo $var | sed 's/[a-z]* //g'
me
 
$ echo $var | tr " " "\n" | sed -n 1p #sed有按地址(行)打印(p)的功能,记得先用tr把空格换成行号
get
$ echo $var | tr " " "\n" | sed -n 5p
me
 
// tr 也可以用来取子串哦,它也可以类似 #和%来“拿掉”一些字符串来实现取子串
$ echo $var | tr -d " "
getthelengthofme
$ echo $var | tr - cd "[a-z]" #把所有的空格都拿掉了,仅仅保留字母字符串,注意-c和-d的用法
getthelengthofme
说明:
[1] %和#的区别是,删除字符的方向不一样,前者在右,后者在左,%%和%,##和#的方向是前者是最大匹配,后者是最小匹配。(好的记忆方法见网中人的键盘记忆法:#$%是键盘依次从左到右的三个键)
[2] tr的-c选项是complement的缩写,即invert,而-d选项是删除的意思,tr -cd "[a-z]"这样一来就变成保留所有的字母啦。

对于字符串的截取,实际上还有一些命令,如果head,tail等可以实现有意思的功能,可以截取某个字符串的前面、后面指定的行数或者字节数。例如:

$ echo "abcdefghijk" | head -c 4
abcd
$ echo -n "abcdefghijk" | tail -c 4
hijk


4.2. 查询子串

// 查询子串在目标串中的位置
$ var="get the length of me"
$ expr index "$var" t        #貌似仅仅可以返回某个字符或者多个字符中第一个字符出现的位置
3 
$ echo $var | awk '{printf("%d\n", match($0,"the"));}'    #awk却能找出字串,match还可以匹配正则表达式
5

// 查询子串,返回包含子串的行(awk,sed都可以实现这些功能,但是grep最擅长)
$ grep "consists of" text   # 查询text文件包含consists of的行,并打印这些行
$ grep "consists[[:space:]]of" -n -H text # 打印文件名,子串所在行的行号和该行的内容
$ grep "consists[[:space:]]of" -n -o text # 仅仅打印行号和匹配到的子串本身的内容
$ awk '/consists of/{ printf("%s:%d:%s\n",FILENAME, FNR, $0)}' text #看到没?和grep的结果一样
$ sed -n -e '/consists of/=;/consists of/p' text #同样可以打印行号


4.3. 子串替换

子串替换就是把某个指定的子串替换成其他的字符串,实际上这里就蕴含了“插入子串”和“删除子串”的操作。例如,你想插入某个字符串到某个子串之 前,就可以把原来的子串替换成”子串+新的字符串“,如果想删除某个子串,就把子串替换成空串。不过有些工具提供了一些专门的用法来做插入子串和删除子串 的操作,所以呆伙还是会专门介绍的。另外,要想替换掉某个子串,一般都是先找到子串(查询子串),然后再把它替换掉的,实质上很多工具在使用和设计上都体 现了这么一点。

概要示例:下面我们把变量var中的空格替换成下划线看看。

// 用{}运算符,还记得么?网中人的教程。
$ var="get the length of me"
$ echo ${var/ /_}        #把第一个空格替换成下划线
get_the length of me
$ echo ${var// /_}        #把所有空格都替换成了下划线了
get_the_length_of_me

// 用awk,awk提供了转换的最小替换函数sub和全局替换函数gsub,类似/和//
$ echo $var | awk '{sub(" ", "_", $0); printf("%s\n", $0);}'
get_the length of me
$ echo $var | awk '{gsub(" ", "_", $0); printf("%s\n", $0);}'
get_the_length_of_me

// 用sed了,子串替换可是sed的特长
$ echo $var | sed -e 's/ /_/'    #s <= substitude
get_the length of me
$ echo $var | sed -e 's/ /_/g'    #看到没有,简短两个命令就实现了最小匹配和最大匹配g <= global
get_the_length_of_me

// 有忘记tr命令么?可以用替换单个字符的
$ echo $var | tr " " "_"
get_the_length_of_me
$ echo $var | tr '[a-z]' '[A-Z]'   #这个可有意思了,把所有小写字母都替换为大写字母
GET THE LENGTH OF ME

使用tr

tr 用来从标准输入中通过替换或删除操作,进行字符转换。 tr 主要用于删除文件中控制字符或进行字符转换。使用 tr 时要转换两个字符串:字符串1用于查询,字符串2用于处理各种转换, tr 刚执行时,字符串1中的字符被映射到字符串2中的字符,然后转换操作开始。

1、将文件 file 中出现的 "abc" 替换为 "xyz"
 
# cat file | tr "abc" "xyz" > new_file
 
【注意】这里,凡是在 file 中出现的 "a" 字母,都替换成 "x" 字母, "b" 字母替换为 "y" 字母, "c" 字母替换为 "z" 字母。而不是将字符串 "abc" 替换为字符串 "xyz" 。
 
 
2、使用 tr 命令“统一”字母大小写
 
(小写 --> 大写)
# cat file | tr [a-z] [A-Z] > new_file
 
(大写 --> 小写)
# cat file | tr [A-Z] [a-z] > new_file
  
 
3、把文件中的数字0-9替换为a-j
 
# cat file | tr [0-9] [a-j] > new_file
   
 
4、删除文件 file 中出现的 "Snail" 字符
 
# cat file | tr -d "Snail" > new_file
 
【注意】这里,凡是在 file 文件中出现的 'S' , 'n' , 'a' , 'i' , 'l' 字符都会被删除!而不是紧紧删除出现的"Snail”字符串。
 
   
5、删除文件 file 中出现的换行 '\n' 、制表 '\t' 字符
 
# cat file | tr -d "\n\t" > new_file
 
不可见字符都得用转义字符来表示的,这个都是统一的。
 
   
6、删除“连续着的”重复字母,只保留第一个
 
# cat file | tr -s [a-zA-Z] > new_file
   
 
7、删除空行
 
# cat file | tr -s "\n" > new_file
   
 
8、删除Windows文件“造成”的 '^M' 字符
 
# cat file | tr -d "\r" > new_file
或者
# cat file | tr -s "\r" "\n" > new_file
 
【注意】这里-s后面是两个参数 "\r" 和 "\n" ,用后者替换前者
   
 
9、用空格符\040替换制表符\011
 
# cat file | tr -s "\011" "\040" > new_file
   
 
10、把路径变量中的冒号 ":" ,替换成换行符 "\n"
 
# echo $PATH | tr -s ":" "\n"

4.4. 插入子串

插入子串:就是在指定的位置插入子串,这个位置可能是某个子串的位置,也可能是从某个文件开头算起的某个长度。通过上面的练习,我们发现这两者之间 实际上是类似的。

公式:插入子串=把"old子串"替换成"old子串+new子串"或者"new子串+old子串"

概要示例::下面在var字符串的空格之前或之后插入一个下划线

// 用{}
$ var="get the length of me"
$ echo ${var/ /_ }        #在指定字符串之前插入一个字符串
get_ the length of me
$ echo ${var// /_ }
get_ the_ length_ of_ me
$ echo ${var/ / _}        #在指定字符串之后插入一个字符串
get _the length of me
$ echo ${var// / _}
get _the _length _of _me

// 其他的还用演示么?这里主要介绍sed怎么用来插入字符吧,因为它的标签功能很有趣
$ echo $var | sed -e 's//_\1/' #和将不匹配到的字符串存放为一个标签,按匹配顺序为\1,\2...
get_ the length of me
$ echo $var | sed -e 's//_\1/g'
get_ the_ length_ of_ me
$ echo $var | sed -e 's//\1_/'
get _the length of me
$ echo $var | sed -e 's//\1_/g'
get _the _length _of _me

// 看看sed的标签的顺序是不是\1,\2....,看到没?\2和\1掉换位置后,the和get的位置掉换了
$ echo $var | sed -e 's/[a?z]? [a?z]? /\2 \1 /g'
the get of length me
// sed还有专门的插入指令,a和i,分别表示在匹配的行后和行前插入指定字符
$ echo $var | sed '/get/a test'
get the length of me
test
$ echo $var | sed '/get/i test'
test
get the length of me

4.5. 删除子串

删除子串:应该很简单了吧,把子串替换成“空”(什么都没有)不就变成了删除么。还是来简单复习一下替换吧。

概要示例::把var字符串中所有的空格给删除掉。

鼓励: 这样一替换不知道变成什么单词啦,谁认得呢?但是中文却是连在一起的,所以中文有多难,你想到了么?原来你也是个语言天才,而英语并不可怕,你有学会它的 天赋,只要你有这个打算。

// 再用{}
$ echo ${var// /}
getthelengthofme
// 再用awk
$ echo $var | awk '{gsub(" ","",$0); printf("%s\n", $0);}'
// 再用sed
$ echo $var | sed 's/ //g'
getthelengthofme
// 还有更简单的tr命令,tr也可以把" "给删除掉,看
$ echo $var | tr -d " "
getthelengthofme


如果要删除掉第一个空格后面所有的字符串该怎么办呢?还记得{}的#和%用法么?如果不记得,回到这一节的还头开始复习吧。(实际上删除子串和取子串未尝 不是两种互补的运算呢,删除掉某些不想要的子串,也就同时取得另外那些想要的子串——这个世界就是一个“二元”的世界,非常有趣)

4.6. 子串比较

这个很简单:还记得test命令的用法么?man test。它可以用来判断两个字符串是否相等的。另外,你发现了“字符串是否相等”和“字符串能否跟另外一个字符串匹配"两个问题之间的关系吗?如果两个 字符串完全匹配,那么这两个字符串就相等了。所以呢,上面用到的字符串匹配方法,也同样可以用到这里。

4.7. 子串排序

差点忘记这个重要的内容了,子串排序可是经常用到的,常见的有按字母序、数字序等正序或反序排列。sort命令可以用来做这个工作,它和其他行处理 命令一样,是按行操作的,另外,它类似cut和awk,可以指定分割符,并指定需要排序的列。

$ var="get the length of me"
$ echo $var | tr ' ' '\n' | sort   #正序排
get
length
me
of
the
$ echo $var | tr ' ' '\n' | sort -r #反序排
the
of
me
length
get


 

猜你喜欢

转载自blog.csdn.net/mainmaster/article/details/120524101