在bash中使用$ SHELL环境变量前面的空格的奇怪行为

时间:2014-01-14 18:56:18

标签: linux bash shell

当我使用以下命令时,一切都按预期工作(一个新的gnome-terminal打开,当前工作目录被更改,终端保持打开状态):

gnome-terminal -e "bash -c 'cd /';$SHELL"
#                                ↑
#                      no space character here

但是当我使用时:

gnome-terminal -e "bash -c 'cd /'; $SHELL"
#                                 ↑
#                           note the space

我可以看到一个打开的终端,但是我看不到当前工作目录是否被更改,因为它立即关闭了终端。

我的问题是:为什么会这样;如果我在第二种情况下放一个空格怎么会错?

2 个答案:

答案 0 :(得分:6)

在第一种情况下,gnome-terminal执行

bash -c "cd /;/bin/bash"

在第二种情况下,它运行

bash -c "cd /;" /bin/bash

第一种情况意味着“评估cd /;/bin/bash”,它将cd并运行一个交互式shell。

第二种情况意味着“评估cd /;$0设置为/bin/bash”,这将运行cd然后退出。

答案 1 :(得分:3)

gnome-terminal使用g_shell_parse_argv自行解析给定的命令,显然不会将;视为单词分隔符,因此如果; }与非空白字符相邻,它被认为是非空白字符的一部分。

如果传递给gnome-terminal的命令中包含shell元字符,则会导致令人惊讶的行为。

我在strace进程中使用gnome-terminal来查看它的作用。第一个命令

gnome-terminal -e "bash -c 'cd /';$SHELL"

导致gnome-terminal运行以下命令

execve("/bin/bash", ["bash", "-c", "cd /;/bin/bash"])

第二个命令

gnome-terminal -e "bash -c 'cd /'; $SHELL"

导致gnome-terminal运行以下命令

execve("/bin/bash", ["bash", "-c", "cd /;", "/bin/bash"])

话虽如此,您还应该注意,bash -c 'cd /'之类的命令不会对其后运行的任何命令的工作目录产生持久影响。所以我认为你键入的第一个命令得到了所需的结果只是因为gnome-terminal解析错误,并且更强大的编写方式将是

gnome-terminal -e "bash -c 'cd /;$SHELL'"