根据我的阅读,将命令放在括号中应该在子shell 中运行它,类似于运行脚本。如果这是真的,如果 x 未导出,它如何查看变量 x?
x=1
Run Code Online (Sandbox Code Playgroud)
(echo $x)在命令行上运行结果为 1
echo $x正如预期的那样,在脚本中运行不会产生任何结果
Learning Bash Book 提到一个子shell只会继承环境变量和文件描述符等,不会继承没有导出的变量:
$ var=15
$ (echo $var)
15
$ ./file # this file include the same command echo $var
$
Run Code Online (Sandbox Code Playgroud)
据我所知,shell 将为()和 for创建两个子shell ./file,但是为什么在这种()情况下,子shell 会识别var变量,尽管它没有导出,而在这种./file情况下它没有识别?
# Strace for ()
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f24558b1a10) = 25617
# Strace for ./file
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f24558b1a10) = 25631
Run Code Online (Sandbox Code Playgroud)
我试图strace弄清楚这是如何发生的,令人惊讶的是我发现 bash 将对克隆系统调用使用相同的参数,所以这意味着分叉进程()和./file应该具有与父进程相同的进程地址空间,那么为什么在这种()情况下,变量是否对子外壳可见,并且这种情况不会发生./file,尽管相同的参数基于克隆系统调用?
$ echo $(echo x; echo y)
x y
$ a='echo x; echo y'
$ echo $($a) # expect 'x y'
x; echo y
Run Code Online (Sandbox Code Playgroud)
eval和的情况下对存储在变量中的命令列表执行命令替换bash -c?echo $(eval $a)并且echo $(bash -c "$a")实际上做了我想要的,但我听说使用 eval 经常是解决问题的错误方法,所以我想知道如何在没有这些命令的情况下进行管理(使用bash -c实际上是一样的)
command-line bash command-substitution variable-substitution