Python 程序是否可以检测到它是否通过shell启动?
如果Python 程序是否可以检测到它是否通过shell启动?,python,python-3.x,shell,subprocess,Python,Python 3.x,Shell,Subprocess,如果shell设置为true,则ls命令将给我一个不同的标准输出。为什么呢 是否有一个基本概念允许程序(ls在本例中)检测它是否通过shell启动 我注意到p1和p2在Windows上共享相同的标准输出,但在Linux上不共享 import subprocess cmd = ['ls', '-la'] # Using shell p1 = subprocess.run(executable=cmd[0], args=cmd[1:], shell=True, text=True, capture
shell
设置为true
,则ls
命令将给我一个不同的标准输出。为什么呢
是否有一个基本概念允许程序(ls
在本例中)检测它是否通过shell启动
我注意到p1
和p2
在Windows上共享相同的标准输出,但在Linux上不共享
import subprocess
cmd = ['ls', '-la']
# Using shell
p1 = subprocess.run(executable=cmd[0], args=cmd[1:], shell=True, text=True, capture_output=True)
# Without using shell
p2 = subprocess.run(executable=cmd[0], args=cmd[1:], shell=False, text=True, capture_output=True)
print(p1.stdout)
print(p2.stdout)
Linux上的输出
total 12
drwxr-xr-x 2 root root 4096 Feb 20 18:25 .
drwx------ 10 root root 4096 Feb 20 18:51 ..
-rw-r--r-- 1 root root 269 Feb 20 18:57 test.py
test.py
通过像您这样查看run()
调用的返回值无法判断
返回值(p1
,它是一个CompletedProcess
)不存储shell的属性:
>>> p1.__dict__
{'args': 'ls', 'returncode': 0, 'stdout': None, 'stderr': None}
通过像您这样查看run()
调用的返回值无法判断
返回值(p1
,它是一个CompletedProcess
)不存储shell的属性:
>>> p1.__dict__
{'args': 'ls', 'returncode': 0, 'stdout': None, 'stderr': None}
Python文档是模糊的,但其行为无法从
strace
中隐藏
您的Python代码:
cmd = ['ls', '-la']
p1 = subprocess.run(executable=cmd[0], args=cmd[1:], shell=True, text=True, capture_output=True)
p2 = subprocess.run(executable=cmd[0], args=cmd[1:], shell=False, text=True, capture_output=True)
变成(strace-f-e execve python3 foo.py
):
这相当于运行这些shell命令,您可以确认,即使这两个命令都是从shell执行的,也会得到相同的结果
ls -c -la # Generally equivalent to: ls -lca
( exec -a -la ls ) # Generally equivalent to: ls
由此我们可以推断出这种行为
如果shell=True
,则调用可执行文件。参数列表是可执行文件
,后跟shell标准-c
标志,后跟args
。这在executable='bash',args=['ls-la']
的情况下更有意义
如果shell=False
,则调用可执行文件。参数列表是args
。这模仿了execve
所以基本上没有,这里没有检测。它只是两种不同的调用ls
,这两种调用都不是您想要的。Python文档是模糊的,但是行为无法从strace
中隐藏
您的Python代码:
cmd = ['ls', '-la']
p1 = subprocess.run(executable=cmd[0], args=cmd[1:], shell=True, text=True, capture_output=True)
p2 = subprocess.run(executable=cmd[0], args=cmd[1:], shell=False, text=True, capture_output=True)
变成(strace-f-e execve python3 foo.py
):
这相当于运行这些shell命令,您可以确认,即使这两个命令都是从shell执行的,也会得到相同的结果
ls -c -la # Generally equivalent to: ls -lca
( exec -a -la ls ) # Generally equivalent to: ls
由此我们可以推断出这种行为
如果shell=True
,则调用可执行文件。参数列表是可执行文件
,后跟shell标准-c
标志,后跟args
。这在executable='bash',args=['ls-la']
的情况下更有意义
如果shell=False
,则调用可执行文件。参数列表是args
。这模仿了execve
所以基本上没有,这里没有检测。这只是两种不同的调用ls
,这两种调用都不是您想要的。这是否回答了您的问题?当args
是一个列表时,我认为shell=True
没有意义。shell将命令行作为单个字符串进行处理。@Barmar我通过以字符串形式发送参数进行了检查,其行为仍然取决于ls
是否作为shell运行。我不确定到底发生了什么,但尝试更改为cmd=['echo',foo',bar']
,您将看到一些有趣的结果。当您使用shell=True
时,将使用可执行文件作为shell。这是否回答了您的问题?当args
是一个列表时,我认为shell=True
没有意义。shell将命令行作为单个字符串进行处理。@Barmar我通过以字符串形式发送参数进行了检查,其行为仍然取决于ls
是否作为shell运行。我不确定到底发生了什么,但尝试更改为cmd=['echo',foo',bar']
,您将看到一些有趣的结果。当您使用shell=True
时,将使用可执行文件
作为shell。如果我的问题不够详细,请原谅。我不是在寻找一种方法来确定Python子进程是否使用shell
属性的特定值运行。我试图理解为什么p1
和p2
有不同的标准输出。这个问题的答案是“因为一个在使用外壳,而另一个没有”。你还想找什么?当然这就是原因。但我的问题是,像ls
这样的程序如何检测它是否通过shell运行?它不像是有一些特殊的值,比如“请作为shell程序运行”作为参数发送给它。它的内部工作原理是什么?AFAIKls
不关心它是否通过shell运行。根据stdout是否为终端,它会更改一些输出格式,但仅此而已。如果我的问题不够详细,请原谅。我不是在寻找一种方法来确定Python子进程是否使用shell
属性的特定值运行。我试图理解为什么p1
和p2
有不同的标准输出。这个问题的答案是“因为一个在使用外壳,而另一个没有”。你还想找什么?当然这就是原因。但我的问题是,像ls
这样的程序如何检测它是否通过shell运行?它不像是有一些特殊的值,比如“请作为shell程序运行”作为参数发送给它。它的内部工作原理是什么?AFAIKls
不关心它是否通过shell运行。它会根据stdout
是否为终端来更改某些输出格式,但仅此而已。