Bash One-Liners Explained (二):操作字符串

这是 Bash One-Liners Explained 系列的第二篇文章。在这一篇里,我会给你们介绍如何用 Bash 来完成各种各样的字符串操作。我会选择用最好的 Bash 做法,各种常见的语法和技巧,向各位阐明如何用 Bash 内置的命令和 Bash 编程语言来完成各式各样的任务。

1. 生成从 a 到 z 的字母表

这一行命令用到了括号展开(Brace expansion)功能,它可以用于生成任意的字符串。{x..y}是一个序列表达式,其中 x 和 y 都是单个字符,这个表达式展开后包含 x 与 y 之间的所有字符。

运行上面的命令会生成从 a 到 z 的所有字母:

2. 生成从 a 到 z 的字母表,字母之间不包含空格

这是一个 99.99% 的人都不知道的非常棒的技巧。如果你在printf命令之后指定一个列表,最终它会循环依次打印每个元素,直到完成为止。

在这一行命令中,printf 的格式为"%c",代表一个字符(character),后面的参数是从 a 到 z 的字符列表,字符之间以空格分隔。所以,当printf执行时,它依次输出每个字符直到所有字符全被处理完成为止。

下面是执行的结果:

输出的结果最后不包含换行符,因为printf的输出格式是"%c",其中并没有包含\n。如果你想输出完整的一行,可以简单地在字符列表后面增加一个$’\n’:

另外一种方式是,通过 echo 来输出 printf 的结果:

这一行命令用到了命令替换功能:执行printf "%c" {a..z}命令然后用执行的输出替换命令。然后,echo 打印输出结果时会带上换行符。

如果你想要每一行仅输出一个字母,在字符后面增加一个换行符:

输出:

如果想要快速地将 printf 的结果保存到变量中,可以使用-v选项:

结果会将abcdefghijklmnopqrstuvwxyz保存到变量alphabet中。

类似地,你也可以利用同样的语法生成一个数字列表,例如从1到100:

输出:

或者,如果你忘记这种方法,可以使用 seq 命令来做这个事情:

3. 输出从 00 到 09 的数字

这里我们又用到了printf的循环输出功能,这一次的输出格式为"%02d ",意思是在输出数字的时候,如果不满两位就用0补齐。同时,输出的元素是 0 到 9的列表(括号展开后的结果)。

输出结果:

如果你使用的是最新的 Bash 4 版本,你可以使用加强的括号展开功能:

老版本不包含该特性。

4. 生成 30 个英文单词

这是一个滥用括号展开的例子,看看最终输出的结果是什么:

是不是很棒?

你可以通过括号展开生成一组单词或者符号的排列。例如:

上面的命令会生成以下结果:a1 a2 a3 b1 b2 b3 c1 c2 c3。首先,它取出第一个括号中的第一个元素a,然后依次与第二个括号{1,2,3}的所有元素组合,生成a1 a2 a3,依此类推。

5. 重复输出 10 次字符串

这一行命令两次利用了括号展开功能,字符串foo与10个空字符串组合,最终生成10分拷贝:

6. 拼接字符串

这一行命令简单地将两个变量的值连接在一起,所以如果x变量的值为foo,而y的值为bar,则结果为foobar

注意,这里的"$x$y"是加了双引号的,如果忘记加了,echo会将$x$y当成常规的命令行参数去解析。所以,如果$x在开头包含-,它就变成一个命令行参数,而不是被 echo 输出的内容。

执行后的输出:

相反,正确书写的方式执行后的结果如下所示:

不过,如果你要将两个字符串相连的结果赋值给变量,是可以将双引号省略的:

7. 分割字符串

假设变量$str的值为foo-bar-baz,如果你想按-分割成多个段并遍历它,可以使用read命令,并且设置 IFS 的值为-:

这里我们使用read x命令从标准输入读取内容,分割后并依次保存到x y z变量中。其中,$x 为foo$y 为 bar$z 为 baz

另外要留意的一处是here-string操作符<<<,可以很方便地将字符串传递给命令的标准输入。在这个例子中,$str的内容传给 read 命令的标准输入。

你也可以将分割后的几个字段保存到数组类型的变量中:

在这里,-a 选项告诉read命令将分割后的元素保存到数组parts中。随后,你可以通过${parts[0]}${parts[1]}${parts[0]}来访问数组的各个元素,或者通过${parts[@]}来访问所有元素。

8. 逐个字符方式处理字符串

这里我们通过指定-n1参数,让read命令依次读入一个字符,类似地,-n2说明每次读入两个字符。

9. 将字符串中的 foo 替换成 bar

这一行命令用到了参数展开的另外一种形式:${var/find/replace},找到$var变量中的find字符串,并将它替换成bar

要想替换所有出现的字符串"foo",请使用${var//find/replace}的形式:

10. 检查字符串是否匹配模式

这一行命令是说,如果$file的值匹配*.zip,则执行if语句里的命令。这种语法下的模式是最简单的通配符(glob pattern)匹配,通配符包括* ? [...]。其中,*可以匹配一个或者多个字符,?只能匹配单个字符,[...]能够匹配任意出现在中括号里面的字符或者一类字符集。

下面是另外一个例子,用来判断回答是否匹配 Y 或者 y:er is Y or y:

11. 检查字符串是否匹配某个正则表达式

这一行命令检查$str是否能够匹配正则表达式[0-9]+\.[0-9]+,即两个数字中间包含一个点号。正则表达式的规范可以通过 man 手册查询: man 3 regex

12.计算字符串的长度

这里我们又用到了参数展开(也可以叫参数替换)的语法: ${#str},它返回$str变量值的长度。

13. 从字符串中提取子串

这一行命令通过子串提取操作,从字符串hello world中取到了子串world。子串提取操作的语法格式为${var:offset:length},它的意思是说从变量var中,提取第offset个位置(下标从0开始计算)开始的总共length个数的字符。在我们这个例子中,忽略了length,默认会返回所有剩余的字符。

下面是另外一个例子,返回$str变量中第7、8位置的两个字符:

输出结果为or

14. 转换成太写

Bash 中的内置命令 declare 可以用于声明一个变量,或者设置变量的属性。在这个例子中,通过指定-u选项,使得变量$var在赋值时,就会自动地将内容转换成大写的格式。现在你 echo 它,可以看到所有内容已经变成大写了:

注意,-u选项也是在 Bash 4 新版本中引入的功能,在低版本下是没有的。类似地,你还可以使用 Bash 4 提供的另外一种参数展开语法${str^^},也可以将字符串转换成太写的格式:

15. 转换成小写

同上面一条类似,-l选项声明变量的小写属性,使得其值转换成小写的格式:

同样,只有 Bash 4 以及以上的版本才支持-l选项。另外一种方式是使用参数展开语法:

我补充一句,如果是 Bash 4 以下,还是老老实实地用tr命令就可以了。

本文完

1 收藏 1 评论

相关文章

可能感兴趣的话题



直接登录
最新评论
跳到底部
返回顶部