大龙的博客

常用链接

统计

最新评论

shell中字符串处理方式

象专业人员那样截断字符串
尽管 basename 和 dirname 是很好的工具,但有时可能需要执行更高级的字符串“截断”,而不只是标准的路径名操作。当需要更强的说服力时,可以利用 bash 内置的变量扩展功能。已经使用了类似于 ${MYVAR} 的标准类型的变量扩展。但是 bash 自身也可以执行一些便利的字符串截断。看一下这些例子:

第一种方法:

${varible##*string} 从左向右截取最后一个string后的字符串

${varible#*string}从左向右截取第一个string后的字符串

${varible%%string*}从右向左截取最后一个string后的字符串

${varible%string*}从右向左截取第一个string后的字符串

"*"只是一个通配符可以不要
$ MYVAR=foodforthought.jpg
$ echo ${MYVAR##*fo}
rthought.jpg
$ echo ${MYVAR#*fo}
odforthought.jpg
在 第一个例子中,输入了 ${MYVAR##*fo}。它的确切含义是什么?基本上,在 ${ } 中输入环境变量名称,两个 ##,然后是通配符 ("*fo")。然后,bash 取得 MYVAR,找到从字符串 "foodforthought.jpg" 开始处开始、且匹配通配符 "*fo" 的 最长 子字符串,然后将其从字符串的开始处截去。刚开始理解时会有些困难,为了感受一下这个特殊的 "##" 选项如何工作,让我们一步步地看看 bash 如何完成这个扩展。首先,它从 "foodforthought.jpg" 的开始处搜索与 "*fo" 通配符匹配的子字符串。以下是检查到的子字符串:   
fo      MATCHES *fo
foo
food
foodf      
foodfo      MATCHES *fo
foodfor
foodfort   
foodforth
foodfortho  
foodforthou
foodforthoug
foodforthought
foodforthought.j
foodforthought.jp
foodforthought.jpg
在搜索了匹配的字符串之后,可以看到 bash 找到两个匹配。它选择最长的匹配,从初始字符串的开始处除去,然后返回结果。

上 面所示的第二个变量扩展形式看起来与第一个相同,但是它只使用一个 "#" -- 并且 bash 执行 几乎同样的过程。它查看与第一个例子相同的子字符串系列,但是 bash 从初始字符串除去 最短 的匹配,然后返回结果。所以,一查到 "fo" 子字符串,它就从字符串中除去 "fo",然后返回 "odforthought.jpg"。

这样说可能会令人十分困惑,下面以一简单方 式记住这个功能。当搜索最长匹配时,使用 ##(因为 ## 比 # 长)。当搜索最短匹配时,使用 #。看,不难记吧!等一下,怎样记住应该使用 '#' 字符来从字符串开始部分除去?很简单!注意到了吗:在美国键盘上,shift-4 是 "$",它是 bash 变量扩展字符。在键盘上,紧靠 "$" 左边的是 "#"。这样,可以看到:"#" 位于 "$" 的“开始处”,因此(根据我们的记忆法),"#" 从字符串的开始处除去字符。您可能要问:如何从字符串末尾除去字符。如果猜到我们使用美国键盘上紧靠 "$" 右边 的字符 ("%),那就猜对了。这里有一些简单的例子,解释如何截去字符串的末尾部分:

$ MYFOO="chickensoup.tar.gz"
$ echo ${MYFOO%%.*}
chickensoup
$ echo ${MYFOO%.*}
chickensoup.tar

正如您所见,除了将匹配通配符从字符串末尾除去之外,% 和 %% 变量扩展选项与 # 和 ## 的工作方式相同。请注意:如果要从末尾除去特定子字符串,不必使用 "*" 字符:

MYFOOD="chickensoup"
$ echo ${MYFOOD%%soup}
chicken

在此例中,使用 "%%" 或 "%" 并不重要,因为只能有一个匹配。还要记住:如果忘记了应该使用 "#" 还是 "%",则看一下键盘上的 3、4 和 5 键,然后猜出来。

第二种方法:${varible:n1:n2}:截取变量varible从n1到n2之间的字符串。

可以根据特定字符偏移和长度,使用另一种形式的变量扩展,来选择特定子字符串。试着在 bash 中输入以下行:

$ EXCLAIM=cowabunga
$ echo ${EXCLAIM:0:3}
cow
$ echo ${EXCLAIM:3:7}
abunga

这种形式的字符串截断非常简便,只需用冒号分开来指定起始字符和子字符串长度。

应用字符串截断

现在我们已经学习了所有截断字符串的知识,下面写一个简单短小的 shell 脚本。我们的脚本将接受一个文件作为自变量,然后打印:该文件是否是一个 tar 文件。要确定它是否是 tar 文件,将在文件末尾查找模式 ".tar"。如下所示:

mytar.sh -- 一个简单的脚本

#!/bin/bash

if [ "${1##*.}" = "tar" ]
then
    echo This appears to be a tarball.
else
    echo At first glance, this does not appear to be a tarball.
fi

要运行此脚本,将它输入到文件 mytar.sh 中,然后输入 "chmod 755 mytar.sh",生成可执行文件。然后,如下做一下 tar 文件试验:

$ ./mytar.sh thisfile.tar
This appears to be a tarball.
$ ./mytar.sh thatfile.gz
At first glance, this does not appear to be a tarball.

好, 成功运行,但是不太实用。在使它更实用之前,先看一下上面使用的 "if" 语句。语句中使用了一个布尔表达式。在 bash 中,"=" 比较运算符检查字符串是否相等。在 bash 中,所有布尔表达式都用方括号括起。但是布尔表达式实际上测试什么?让我们看一下左边。根据前面所学的字符串截断知识,"${1##*.}" 将从环境变量 "1" 包含的字符串开始部分除去最长的 "*." 匹配,并返回结果。这将返回文件中最后一个 "." 之后的所有部分。显然,如果文件以 ".tar" 结束,结果将是 "tar",条件也为真。

您可能会想:开始处的 "1" 环境变量是什么。很简单 -- $1 是传给脚本的第一个命令行自变量,$2 是第二个,以此类推。
1、
我用在判断apache安装版本的时候用的
isher@isher-ubuntu:~$ aa=apache_2.0.59
isher@isher-ubuntu:~$ echo $aa | awk -F_ '{ print $1; }' #F后面的下划线分割成了apache和2.0.59两个变量 $1即第一个

2、写进度条时候参考过,后来考虑到成本大于使用,就放弃了
isher@isher-ubuntu:~$ a=12345678
isher@isher-ubuntu:~$ echo $a|cut -b 2-5
isher@isher-ubuntu:~$ 2345 #这里是输出结果

cut:对标准输入的字符串进行处理
cut -bn-m:以byte为单位,从第n个byte开始,取m个
cut -bn,m:以byte为单位,截取第n,m个byte
cut -b-n,m:以byte为单位,截取1-n,和第m个
-c:以charactor为单位
-d:指定分隔符,默认为tab
-s:使标准输入中没有delimeter
cut -f1:截取第1个域
3、字符串截取前后部分内容
echo ${变量#开始字符串*结束字符串} #表示掐头,因为键盘上#在$($就是变量,这样便于记住)前面,一个表示最小匹配
echo ${变量%开始字符串r*结束字符串} # %表示去尾,因为键盘上%在$后面,一个表示最小匹配

echo ${变量##开始字符串*结束字符串} 两个表示最大匹配
echo ${变量%%开始字符串r*结束字符串} 两个表示最大匹配
总结记忆方法
键盘上#$%三个字符连续的,以$为变量提示符,#即截取变量前的字符,表示截取后面字符

例子
isher@isher-ubuntu:~$ aa="No such file or directory" #编写此文档时,正好shell开着,提示这行话~ *_^
isher@isher-ubuntu:~$ echo ${aa#No*dir}
ectory # 这里就是输出结果,将No such file or directory 之间的都删除了,得到就是ectory
截取后部的意思相同

isher在简单说一下##的意思
isher@isher-ubuntu:~$ aa="No such file or directory" #截取e之后的内容,此句话中有两个e
如果标记一个#
isher@isher-ubuntu:~$ echo ${aa#No*e}
则结果为 or directory
isher@isher-ubuntu:~$ echo ${aa##No*e}
##的结果为 ctory
截取后部的意思相同

4、在写脚本的时候,有一个替换的问题,特提出
echo ${变量/旧的内容/新的内容} #替换一个
echo ${变量//旧的内容/新的内容} #替换所有

例子:
isher@isher-ubuntu:~$ aa="No such file or directory"
isher@isher-ubuntu:~$ echo ${aa/o/a}
Na such file or directory #这里仅替换了第一个单词No的o变为了a

isher@isher-ubuntu:~$ aa="No such file or directory"
isher@isher-ubuntu:~$ echo ${aa//o/a}
Na such file ar directary #这里可以看到,替换这句话(变量)的所有的o为了a了

1.得到字符串长度
方法一:
$echo ${#variable}

代码:
~$ x="this is a test"
~$ echo ${#x}
14
方法二:
$expr length "$variable"

代码:
~$ x="this is a test"
~$ expr length "$x"
14
方法三:
$expr "$variable" : ".*"
code:
代码:
~$ x="this is a test"
~$ expr "$x" : ".*"
14
2.查找字符串子串位置
方法:
$expr index "$variable" "substring"
code:
代码:
~$ x="this is a test"
~$ expr index "$x" "is"
3
~$ expr index "$x" "t"
1
(ps:如果出现重复,好象只能查到第一个,第二个,第三个,...,怎么查到呢???)
3.得到字符串子字符串
方法一:
$echo ${variable:position:length}

代码:
~$ x="this is a test"
~$ echo ${x:1:5}
his i
方法二:
$expr substr "$variable" startposition length
代码:
~$ x="this is a test"
~$ expr substr "$x" 1 5
this
(ps:注意方法一和方法二中位置的区别!)
4.匹配正则表达式之匹配长度
方法:
$expr match "$x" "string"

代码:
~$ x="this is a test"
~$ expr match "$x" "his"
0
~$ expr match "$x" "this"
4
~$ expr match "$x" "."
1
5.字符串的掐头去尾
方法:
$echo ${variable#startletter*endletter} # #表示掐头,因为键盘上#在$前面,一个表示最小匹配
$echo ${variable##tartletter*endletter} 两个表示最大匹配
$echo ${variable%startletter*endletter} # %表示去尾,因为键盘上%在$后面,一个表示最小匹配
$echo ${variable%%startletter*endletter} 两个表示最大匹配

代码:
~$ x="this is a test"
~$ echo ${x#t}
his is a test
~$ echo ${x#t*h}
is is a test
~$ echo ${x#t*s}
is a test

~$ echo ${x##t*s}
t

~$ echo ${x%t}
this is a tes
~$ echo ${x%s*t}
this is a te
~$ echo ${x%e*t}
this is a t

~$ echo ${x%%i*t}
th

6.字符(串)的替换
方法:
$echo ${variable/oldletter/newletter} #替换一个
$echo ${variable//oldletter/newletter} #替换所有

代码:
~$ x="this is a test"
~$ echo ${x/i/m}
thms is a test
~$ echo ${x//i/m}

posted on 2010-10-12 19:42 大龙 阅读(465) 评论(0)  编辑 收藏 引用


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理