Unix的字符串处理能力,说实话确实不算强。不像某些高级语言里随手就有 length() 这类现成函数,想对字符串做点操作,往往得搬出 expr 命令,再搭配一堆通配符来绕路实现。虽说麻烦归麻烦,但只要摸清楚每种处理方式的脾气和坑在哪里,对症下药,照样能找着简单利落的办法来搞定日常问题。 一、对用户
Unix的字符串处理能力,说实话确实不算强。不像某些高级语言里随手就有 length() 这类现成函数,想对字符串做点操作,往往得搬出 expr 命令,再搭配一堆通配符来绕路实现。虽说麻烦归麻烦,但只要摸清楚每种处理方式的脾气和坑在哪里,对症下药,照样能找着简单利落的办法来搞定日常问题。
系统工程师时常需要检查用户输入的字符串长度。比如写个登录程序,为了安全起见,可能会限制密码最少要六位以上。这其实就是统计输入字符串的长度:不够就提醒,够就存。用 if 或 while 循环配合条件判断,条件则交给 expr 关键字来实现。
长期稳定更新的攒劲资源: >>>点此立即查看<<<
要判断用户输入的密码长度,可以这样写:
expr "$userpasswd" : '.*'
写这条命令有几个需要注意的规则。首先,expr 需要两个表达式,中间用英文冒号隔开。冒号左边是要处理的字符串(变量),右边是正则表达式。顺序很严格,写反了就没法用。其次,待处理的字符串要用双引号括起来——这跟普通命令里变量的用法不一样。平时变量不加引号,加引号反而被当作常量;但在这里,变量必须用双引号包住,否则结果会出错。不少工程师在这上面吃过亏。最后,右边的正则表达式通常要用单引号引起来,比如 '.*' 表示匹配所有字符。不加单引号,系统可能报语法错误。
有时候需要截取字符子串来完成特定任务。比如系统工程师想根据系统时间给文件命名,规则是年份后两位加月份,例如 0906 表示09年6月。每个月生成一个单独的日志文件,这个命名格式挺合理。但现实中,用 date 命令截取年份,拿到的往往是四位数字(如 2009),而不是两位。那怎么才能只取后两位呢?
这时候就要用到 expr 命令的另一个功能——截取子串。一般来说,expr 在字符串处理上主要有三个用途:求长度、截子串、查位置。如果跟其他命令组合,还能实现更复杂的操作。不过,在Unix系统中,能直接用自带命令解决的问题,优先用自带命令。比如 date %w 就能显示今天是星期几,完全没必要用 expr 去折腾。只有当系统没有现成工具时,才搬出 expr 这个万能方案。虽然它能完成所有截取工作,但代码写起来不如自带命令那么清爽。
回到例子,要截取年份的后两位,可以借助转义字符这样写:
$expr "2009" : '..\(..\)'
这里的 \ 是转义字符,正则表达式的意思是只取字符串的最后两个字符,忽略其他。如果字符串来自变量,把 2009 换成变量名就行。实际做文件命名时,先截取年份后两位,再把月份拼上去,就搞定了。
难点在于正则表达式的写法。只要写对正则,expr 的功能不比数据库里的字符串函数差,甚至更灵活。但是经验不足的工程师往往在这里卡壳——就连老手也偶尔会犹豫。想提高正则功底,最有效的办法是多看别人写的脚本,模仿多了自然就顺手了。
假设某个目录下有很多 .sh 文件(Unix配置文件,本质上就是文本),现在需要把所有扩展名改成 .txt。手工一个个改太慢,批量处理才是正道。
批量改名可以借助 for 循环实现。循环体内有两种思路。第一种是用 expr 命令:文件名其实就是字符串,先用 expr 截取扩展名之前的部分,存到变量 filenameshort 里,然后用 mv 或 rename 重命名为 $filenameshort.txt。但问题是文件名长度不固定,正则表达式写起来很麻烦,要把不带扩展名的部分完整截出来,难度不小。
这里介绍另一个更合适的命令——basename。它也是一个字符串处理工具,基本格式是 basename text1 text2,功能是从第一个字符串中去掉第二个字符串的内容。例如 basename setup.sh sh 会返回 setup.(去掉 sh 后的结果)。用它来批量改名就简单多了:在循环中调用 basename 去掉原扩展名,再拼上新的扩展名,完全不需要正则表达式。代码写起来清晰,也容易维护。
从这个案例可以总结一个基本原则:无论截取字符串还是其他操作,优先找系统自带命令(比如 date 的选项参数);如果没有,再看 basename 这类不需要正则的工具;实在不行了,才用 expr。原因很简单——正则表达式虽然强大,但写起来容易出错,尤其在复杂场景下。测长度还行,真要干截取、定位的细活,没点功力很难一次写对。
侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述