$...`和`...`有什么区别?

问题描述

$( ... )( ... )以及. source)之间有什么区别?


在编写shell脚本的开始,我就知道$( ... )是合适的,如果我想使用命令的输出,例如对于变量:

size=$( wc -c < /path/to/file )

然后我发现,如果我想执行命令(在子外壳中),可以使用( ... ),等待它退出并使用其输出文件,例如:

( echo -e "a lot of data,if everything worked... ;-)" > /path/to/file )

有趣的是,它也可以与$( ... )一起使用,但是给出了某种神秘的错误消息scriptname: line 1: : Command not found.

$( echo -e "a lot of data,if everything worked... ;-)" > /path/to/file )

为什么$( ... )不能在两个用例中都能正常工作?考虑到错误消息,我想原因是这样的:$( ... )“即使在shell上也强制输出一个空的输出”,尽管没有,但是( ... )只是执行命令,并不关心输出。是吗?


我知道在当前shell中也有. (别名为source)来执行命令,关于该功能,它似乎更像$( ... )。 / p>

或者. ( ... )间的区别还不仅仅在于在我不知道的当前子外壳程序中执行命令,还是其他原因?

解决方法

在子外壳中运行的命令(无论是否在子外壳中运行)在执行这些命令后都不会与外壳本身发生任何交互。

$ echo echo poo
echo poo

相比之下,shell完成后会评估命令替换:

$ $(echo echo poo)
poo

$ var=$(echo echo poo)

$ echo "$var"
echo poo

$ $(echo "$var")   # expands to the first line (but is unnecessarily redundant)
poo

$ $var             # more succinct version of the previous line
poo

当然,如果您重定向命令替换的输出,则外壳程序最终将评估一个空字符串。

.命令(或者在Bash和其他一些非POSIX Shell中,其同义词source)评估文件中的一系列命令。从某种意义上讲,这与命令替换有些相似,但是后者使您可以捕获和处理求值结果(从某种意义上说,shell的整个目的用于求值)。 / p>

命令替换实际上可以用于在任何地方计算表达式,而.或子shell只能在shell接受命令的地方使用。看一下这些体操:

$ $(echo e)$(echo c)$(echo h)$(echo o) "poo"
poo

$ echo p$(printf x | wc -l | tr -d ' ' | tr '1' 'o')o
poo

$ ech$(echo o poo)
poo

就像您发现的那样,当您希望一组命令共享一些文件描述符时,子外壳会很有用;

( printf '%s\n' 'Subject: hello' \
    'MIME-version: 1.0' \
    'Content-type: application/octet-stream' \
    'Content-transfer-encoding: base64' \
    ''
  base64 binaryfile ) |
sendmail -oi [email protected]

或者如果您想限制某些环境更改的范围;

for subdir in */; do
  ( cd "$subdir"
    condiments=$(cat spice.txt)
    export condiments
    make -s dinner )
# back in parent dir
# $condiments is back to its old value
# probably unset,and not exported
done
,

$( cmd )执行cmd,然后尝试执行其输出。所以

$( echo -e "a lot of data,if everything worked... ;-)" > /path/to/file )

执行将数据写入/path/to/file且不产生任何输出的命令。 Shell获取该输出(空字符串)并尝试执行它,生成您看到的错误消息。