当我打开命令行时,我希望它在当前活动窗口所在的同一工作目录中启动。 因此,我编写了一个python脚本,找出了正确的路径。它将打开终端的命令作为参数。在此参数中,它将占位符替换为所需目录,并使用
执行命令subprocess.Popen(cmd, stderr=subprocess.PIPE, shell=True)
字符串cmd
已正确汇编为:
xterm -e 'cd '\''/mnt/data/software/computer/tools/i3'\''; /usr/bin/bash'
如果我在bash中执行此命令,它会根据需要在正确的目录中打开xterm。 如果我从python脚本执行此命令,则xterm 不打开。
区别在哪里?
其他信息:
我正在使用Python 3.6.5。
echo $SHELL
返回/bin/bash
。
我的i3配置中脚本的键绑定:
bindsym $mod+Return exec "/mnt/data/software/computer/tools/i3/i3_launch_cwd.sh \\"xterm -e 'cd %{cwd}; /usr/bin/bash'\\""
(这个shell脚本只是一个简单的包装器,它将stderr重定向到日志文件以进行调试)
在bash中执行以下命令后,xterm甚至可以从python中打开:
xrdb -merge -I$HOME ~/.Xresources
Xresources中的相关行是
xterm*faceName: DejaVu Sans Mono Book
为什么会有所作为?
解决方案:
感谢Charles Duffy的评论,我发现了这个问题。
在我的python脚本中,我使用stderr=subprocess.PIPE
重定向stderr,但我忘了阅读stderr。
在加载设置字体的Xresources文件之前,xterm会向stderr发出一条警告,指出无法加载字体。
xterm有一个非常小的缓冲区。因为我的程序没有读取stderr,所以缓冲区未被清除,xterm被阻止。
更换
subprocess.Popen(cmd, stderr=subprocess.PIPE, shell=True)
带
p = subprocess.Popen(cmd, stderr=subprocess.PIPE, shell=True)
out, err = p.communicate()
sys.stderr.write(err)
会解决问题。 但是因为我没有对stderr做任何事情,所以不需要首先重定向它。 所以我现在正在使用
subprocess.Popen(cmd, shell=True)
答案 0 :(得分:4)
不要使用shell=True
;它不适合您的使用案例。
import subprocess
try:
from pipes import quote # Python 2
except ImportError:
from shlex import quote # Python 3
dir='/mnt/data/software/computer/tools/i3'
p = subprocess.Popen(['xterm', '-e', 'cd %s && exec bash' % quote(dir)])
但是,您可以通过subprocess.Popen
为您设置目录来简化此操作:
dir='/mnt/data/software/computer/tools/i3'
p = subprocess.Popen(['xterm', '-e', 'bash'], cwd=dir)
也就是说,shell=True
100%等同于运行sh -c '...command...'
,其中您的命令的文字文字位于...command...
;这正是它在实践中的作用。
请注意,我上面删除了stderr=subprocess.PIPE
。您可以重新添加,但前提是您已将代码实际读取内容写入stderr,方法是调用communicate()
。