bash之命令替换(command substitution)

您所在的位置:网站首页 substitude和substitution bash之命令替换(command substitution)

bash之命令替换(command substitution)

2023-08-31 08:00| 来源: 网络整理| 查看: 265

写在前面

bash在做完参数扩展(请参阅《bash之参数扩展》)之后,紧接着需要做的是命令替换(command substitution)。

命令替换相对其它扩展来说要简单一些,这篇博文就来简单了解下什么是shell的命令替换功能以及应该注意的事项。

 

什么是命令替换

我们来看bash手册里是怎么说的:

Command substitution allows the output of a command to replace the command itself.

再看看Wikpedia是怎么说的:

In computing, command substitution is a facility that allows a command to be run and its output to be pasted back on the command line as arguments to another command. 

OK, 很清晰了,所谓命令替换就是:子命令先运行,最后获取这个子命令的标准输出(stdout)用来重组命令行。

 

命令替换的两种形式

命令替换有两种形式,如下:

$( COMMANDS ) ` COMMANDS ` 废话不多说,先来看两个例子吧。

(1)获取上个星期天的日期。

[16:57:44@astrol:~]$ echo `date -d "last sunday" +%Y-%m-%d` 2018-12-16 [16:58:09@astrol:~]$ echo $(date -d "last sunday" +%Y-%m-%d) 2018-12-16

(2)列出/etc目录下以ren结尾的文件。

[17:09:47@astrol:/etc]$ for f in $(ls /etc/*.ren); do echo "$f"; done /etc/hosts.ren /etc/nsswitch.conf.ren /etc/ntp.conf.ren /etc/rsyslog.conf.ren

通过这两个例子可以发现,使用$(COMMAND)或者`COMMAND`可以让COMMAND提前整个命令运行,最后将COMMAND的标准输出(stdout)内容插入到COMMAND符号处。

 

命令替换的两个特点

Bash performs the expansion by executing COMMAND in a subshell environment and replacing the command substitution with the standard output of the command, (1)with any trailing newlines deleted.  Embedded newlines are not deleted, but they may be removed during word splitting. (2)The command substitution '$(cat FILE)' can be replaced by the equivalent but faster '$(< FILE)'.

通过阅读bash手册中这一小段,我们可以总结出命令替换具备两个特点。

特点一: bash会将子命令标准输出的最后换行符全部删除掉。

我们通过以下例子来增加感性认识:

[10:01:21@astrol:~]$ echo -n -e "a\nb\nc\n\n\n" a b c [10:01:25@astrol:~]$ echo -n -e "a\nb\nc\n\n\n" | hexdump -C 00000000 61 0a 62 0a 63 0a 0a 0a |a.b.c...| 00000008 [10:01:26@astrol:~]$ echo -n -e $(echo -n -e "a\nb\nc\n\n\n") a b c[10:02:12@astrol:~]$ echo -n -e $(echo -n -e "a\nb\nc\n\n\n") | hexdump -C 00000000 61 20 62 20 63 |a b c| 00000005 [10:03:51@astrol:~]$ echo -n -e "$(echo -n -e "a\nb\nc\n\n\n")" a b c[10:04:27@astrol:~]$ echo -n -e "$(echo -n -e "a\nb\nc\n\n\n")" | hexdump -C 00000000 61 0a 62 0a 63 |a.b.c| 00000005 [10:04:31@astrol:~]$

通过观察echo -n -e $(echo -n -e "a\nb\nc\n\n\n")的结果可以发现,命令替换的确将最后的三个“\n”吃掉了,中间的两个“\n”是由于后续的单词分割(word splitting)根据变量IFS的值替换成了空格(0x20)。那么通过双引号括起来为什么中间的两个“\n”就保留了呢? 回答这个问题请看下图:

可以看到,当用双引号扩起来之后,bash跳过了单词分割(word splitting)和路径扩展(pathname expansion)这两项扩展,自然就保留了中间的两个“\n”。其实在bash手册的最后也给出了解释:

If the substitution appears within double quotes, word splitting and filename expansion are not performed on the results.

那命令替换为什么默认会删除最后的换行符?是处于什么考虑吗?

这里可以大胆地猜测下:因为命令替换的结果经常交给外部命令,不应该让结果有换行的行为,所以默认将最后的换行符删除掉。

 

特点二:  '$(cat FILE)'在命令替换中更有效的形式是'$(< FILE)'

如果我们通过命令替换仅仅是想获得某个文件的内容,那么我们可以使用$(



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3