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程序运行”作为参数发送给它。它的内部工作原理是什么?AFAIK
ls
不关心它是否通过shell运行。根据stdout是否为终端,它会更改一些输出格式,但仅此而已。如果我的问题不够详细,请原谅。我不是在寻找一种方法来确定Python子进程是否使用
shell
属性的特定值运行。我试图理解为什么
p1
p2
有不同的标准输出。这个问题的答案是“因为一个在使用外壳,而另一个没有”。你还想找什么?当然这就是原因。但我的问题是,像
ls
这样的程序如何检测它是否通过shell运行?它不像是有一些特殊的值,比如“请作为shell程序运行”作为参数发送给它。它的内部工作原理是什么?AFAIK
ls
不关心它是否通过shell运行。它会根据
stdout
是否为终端来更改某些输出格式,但仅此而已。