问题描述
$( ... )
和( ... )
以及.
(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获取该输出(空字符串)并尝试执行它,生成您看到的错误消息。