Я хотел бы понять, как подпроцесс. Открыто работает на windows при shell=False
. В частности, как среда или расширение переменной учитывается базовым алгоритмом?
Рассмотрим следующий простой тест:
import os
import subprocess
import textwrap
def truncate(string, width):
if len(string) > width:
string = string[:width - 3] + '...'
return string
if __name__ == '__main__':
index = 0
commands = [
["where", "find.exe"],
"where find.exe",
[r"c:\windows\system32\where.exe", "find.exe"],
r"c:\windows\system32\where.exe find.exe",
["find.exe", "--version"],
"find.exe --version",
r"D:\sources\personal\sublimemerge\Git\usr\bin\find.exe --version",
]
def run(target, shell):
global index
label = (
f'{index:<2}) subprocess.run('
f'{repr(target)}, shell={shell}, '
f'stdout=subprocess.PIPE, stderr=subprocess.STDOUT, '
f'universal_newlines=True)'
)
label = f"{label:<160}"
try:
x = subprocess.run(target, shell=shell, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, universal_newlines=True)
print(f"{label} - returncode={x.returncode} - {repr(truncate(x.stdout, 40))}")
except Exception as e:
print(f"{label} - exception={repr(truncate(str(e), 90))}")
index += 1
for c in commands:
run(c, shell=True)
run(c, shell=False)
Где результат выглядит следующим образом:
0 ) subprocess.run(['where', 'find.exe'], shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) - returncode=0 - 'D:\\sources\\personal\\sublimemerge\\Git\\...'
1 ) subprocess.run(['where', 'find.exe'], shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) - returncode=0 - 'D:\\sources\\personal\\sublimemerge\\Git\\...'
2 ) subprocess.run('where find.exe', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) - returncode=0 - 'D:\\sources\\personal\\sublimemerge\\Git\\...'
3 ) subprocess.run('where find.exe', shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) - returncode=0 - 'D:\\sources\\personal\\sublimemerge\\Git\\...'
4 ) subprocess.run(['c:\\windows\\system32\\where.exe', 'find.exe'], shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) - returncode=0 - 'D:\\sources\\personal\\sublimemerge\\Git\\...'
5 ) subprocess.run(['c:\\windows\\system32\\where.exe', 'find.exe'], shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) - returncode=0 - 'D:\\sources\\personal\\sublimemerge\\Git\\...'
6 ) subprocess.run('c:\\windows\\system32\\where.exe find.exe', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) - returncode=0 - 'D:\\sources\\personal\\sublimemerge\\Git\\...'
7 ) subprocess.run('c:\\windows\\system32\\where.exe find.exe', shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) - returncode=0 - 'D:\\sources\\personal\\sublimemerge\\Git\\...'
8 ) subprocess.run(['find.exe', '--version'], shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) - returncode=0 - 'find (GNU findutils) 4.6.0\nCopyright ...'
9 ) subprocess.run(['find.exe', '--version'], shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) - returncode=2 - 'FIND: Parameter format not correct\n'
10) subprocess.run('find.exe --version', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) - returncode=0 - 'find (GNU findutils) 4.6.0\nCopyright ...'
11) subprocess.run('find.exe --version', shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) - returncode=2 - 'FIND: Parameter format not correct\n'
12) subprocess.run('D:\\sources\\personal\\sublimemerge\\Git\\usr\\bin\\find.exe --version', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) - returncode=0 - 'find (GNU findutils) 4.6.0\nCopyright ...'
13) subprocess.run('D:\\sources\\personal\\sublimemerge\\Git\\usr\\bin\\find.exe --version', shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) - returncode=0 - 'find (GNU findutils) 4.6.0\nCopyright ...'
Первый вопрос, который мне приходит в голову: зачем мне указывать полный путь к исполняемому файлу, когда shell=False
? Почему env
не рассматривается так же, как при использовании shell=True
? На самом деле ... посмотрите на случаи 5,7
, просто взглянув на них, можно подумать, что env
учитывается.
Полагаю, все сводится к пониманию того, как env
передается CreateProcess вызовом cpython _winapi. c .