根据我的阅读,将命令放在括号中应该在子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
,尽管相同的参数基于克隆系统调用?
我正在阅读一本 Linux shell 脚本书,并发现以下警告:
“命令替换会创建所谓的子外壳来运行封闭的命令。子外壳是从运行脚本的外壳生成的单独子外壳。因此,您在脚本中创建的任何变量都不能用于子外壳命令”。
我尝试在当前 bash shell 的 CLI 中创建一个变量,然后进入子 shell 检查是否可以在屏幕上打印它。所以是的,我做不到,似乎是根据上面的引文。但是,我已经使用命令替换运行了以下脚本:
#!/bin/bash
var=5.5555
ans=$(echo $var)
echo $ans
Run Code Online (Sandbox Code Playgroud)
结果是:
5.5555
Run Code Online (Sandbox Code Playgroud)
据我了解,它不应该打印 var 的值,因为子外壳不应该能够“看到它”。为什么会发生?