#1.概述截断字符串
截断字符串是将初始字符串截断成较小的独立块,它是一般 shell 脚本每天执行的任务之一。很多时候,shell
脚本需要采用全限定路径,并找到结束的文件或目录。虽然可以用 bash 编码实现(而且有趣),但标准 basename UNIX
可执行程序可以极好地完成此工作:
---------------bash------------------
$ basename /usr/local/share/doc/foo/foo.txt
foo.txt
$ basename /usr/home/drobbins
drobbins
-----------------------------------
basename 是一个截断字符串的极简便工具,用于从文件的全限定路径中取出结束的文件或目录。它的相关命令 dirname 返回 basename 丢弃的“另”一部分路径。
---------------bash------------------
$ dirname /usr/local/share/doc/foo/foo.txt
/usr/local/share/doc/foo
$ dirname /usr/home/drobbins/
/usr/home
-----------------------------------
#2.命令替换
如何创建一个包含可执行命令结果的环境变量呢。这很容易:
---------------bash------------------
$ MYDIR=`dirname /usr/local/share/doc/foo/foo.txt`
$ echo $MYDIR
/usr/local/share/doc/foo
-----------------------------------
上面所做的称为“命令替换”。此例中有几点需要指出。在第一行,简单地将要执行的命令以 “反引号” 括起。那不是标准的单引号,而是键盘中通常位于 Tab 键之上的单引号。当然我们可以用 bash 备用命令替换语法来做同样的事:
---------------bash------------------
$ MYDIR=$(dirname /usr/local/share/doc/foo/foo.txt)
$ echo $MYDIR
/usr/local/share/doc/foo
-----------------------------------
如您所见,bash 提供多种方法来执行完全一样的操作。使用命令替换可以将任何命令或命令管道放在 ` ` 或 $( ) 之间,并将其分配给环境变量。很方便,不是吗!下面是一个例子,演示如何在命令替换中使用管道:
---------------bash------------------
MYFILES=$(ls /etc | grep pa)
bash-2.03$ echo $MYFILES
pam.d passwd
-----------------------------------
#3.象专业人员那样截断字符串
尽管 basename 和 dirname
是很好的工具,但有时可能需要执行更高级的字符串“截断”,而不只是标准的路径名操作。当需要更强的说服力时,可以利用 bash
内置的变量扩展功能。已经使用了类似于 ${MYVAR} 的标准类型的变量扩展。但是 bash
自身也可以执行一些便利的字符串截断。看一下这些例子:
---------------bash------------------
$ 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"
通配符匹配的子字符串。以下是检查到的子字符串:
-----------------------------------
f
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 变量扩展字符。在键盘上,紧靠 "$" 左边的是 "#"。这样,可以看到:"#" 位于 "$"
的“开始处”,因此(根据我们的记忆法),"#" 从字符串的开始处除去字符。您可能要问:如何从字符串末尾除去字符。如果猜到我们使用美国键盘上紧靠
"$" 右边 的字符 ("%),那就猜对了。这里有一些简单的例子,解释如何截去字符串的末尾部分:
---------------bash------------------
$ MYFOO="chickensoup.tar.gz"
$ echo ${MYFOO%%.*}
chickensoup
$ echo ${MYFOO%.*}
chickensoup.tar
-----------------------------------
正如您所见,除了将匹配通配符从字符串末尾除去之外,% 和 %% 变量扩展选项与 # 和 ## 的工作方式相同。请注意:如果要从末尾除去特定子字符串,不必使用 "*" 字符:
---------------bash------------------
MYFOOD="chickensoup"
$ echo ${MYFOOD%%soup}
chicken
-----------------------------------
在此例中,使用 "%%" 或 "%" 并不重要,因为只能有一个匹配。还要记住:如果忘记了应该使用 "#" 还是 "%",则看一下键盘上的 3、4 和 5 键,然后猜出来。
可以根据特定字符偏移和长度,使用另一种形式的变量扩展,来选择特定子字符串。试着在 bash 中输入以下行:
---------------bash------------------
$ EXCLAIM=cowabunga
$ echo ${EXCLAIM:0:3}
cow
$ echo ${EXCLAIM:3:7}
abunga
-----------------------------------
这种形式的字符串截断非常简便,只需用冒号分开来指定起始字符和子字符串长度。
#4.应用字符串截断
现在我们已经学习了所有截断字符串的知识,下面写一个简单短小的 shell 脚本。我们的脚本将接受一个文件作为自变量,然后打印:该文件是否是一个 tar 文件。要确定它是否是 tar 文件,将在文件末尾查找模式 ".tar"。如下所示:
-----------------------------------
#!/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 文件试验:
---------------bash------------------
$ ./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 是第二个,以此类推。好,已经回顾了功能,下面来初探 "if" 语句。
#5.If 语句
与大多数语言一样,bash 有自己的条件形式。在使用时,要遵循以上格式;即,将 "if" 和 "then" 放在不同行,并使
"else" 和结束处必需的 "fi" 与它们水平对齐。这将使代码易于阅读和调试。除了 "if,else" 形式之外,还有其它形式的 "if"
语句:
-----------------------------------
if [ condition ]
then
action
fi
-----------------------------------
只有当 condition 为真时,该语句才执行操作,否则不执行操作,并继续执行 "fi" 之后的任何行。
-----------------------------------
if [ condition ]
then
action
elif [ condition2 ]
then
action2
.
.
.
elif [ condition3 ]
then
else
actionx
fi
----------------------------------
以上 "elif" 形式将连续测试每个条件,并执行符合第一个 真 条件的操作。如果没有条件为真,则将执行 "else" 操作,如果有一个条件为真,则继续执行整个 "if,elif,else" 语句之后的行。
阅读(865) | 评论(1) | 转发(0) |