当我使用以下命令时,一切都按预期工作(一个新的gnome终端打开,当前工作目录更改,终端保持打开):
gnome-terminal -e "bash -c 'cd /';$SHELL"
# ↑
# no space character here
但当我使用:
gnome-terminal -e "bash -c 'cd /'; $SHELL"
# ↑
# note the space
我可以看到一个打开的终端,但我看不出当前工作目录是否发生了更改,因为终端会立即关闭。
我的问题是:为什么会发生这种情况;如果我在第二种情况下放一个空格,怎么会错呢?
在第一种情况下,gnome终端执行
bash -c "cd /;/bin/bash"
在第二种情况下,它运行
bash -c "cd /;" /bin/bash
第一种情况的意思是"评估cd /;/bin/bash
",它将cd并运行一个交互式shell。
第二种情况表示"在$0
设置为/bin/bash
的情况下评估cd /;
",它将运行cd,然后退出。
gnome-terminal
使用g_shell_parse_argv对给定的命令进行自己的解析,该语法显然不认为;
是单词分隔符,因此如果;
与非空白字符相邻,则认为它是该非空白字符单词的一部分。
如果传递给gnome-terminal
的命令中有shell元字符,这可能会导致令人惊讶的行为
我在gnome-terminal
进程中使用了strace
来查看它的作用。第一个命令
gnome-terminal -e "bash -c 'cd /';$SHELL"
导致gnome终端运行以下命令
execve("/bin/bash", ["bash", "-c", "cd /;/bin/bash"])
第二个命令
gnome-terminal -e "bash -c 'cd /'; $SHELL"
导致gnome终端运行以下命令
execve("/bin/bash", ["bash", "-c", "cd /;", "/bin/bash"])
话虽如此,你还应该注意到,像bash -c 'cd /'
这样的命令不会对它之后运行的任何命令的工作目录产生持久的影响。所以我认为,你键入的第一个命令之所以能得到所需的结果,只是因为gnome终端解析错误,而一种更稳健的编写方法是
gnome-terminal -e "bash -c 'cd /;$SHELL'"