簡體   English   中英

Python的subprocess.Popen和shell = True與真實shell之間的區別

[英]The difference between Python's subprocess.Popen with shell=True and a real shell

當我打開命令行時,我希望它從與當前活動窗口相同的工作目錄中啟動。 因此,我寫了一個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。 在加載設置字體xterm的Xresources文件之前,會向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)

不要使用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()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM