gpt4 book ai didi

python - bash shellshock 更新导致脚本行为不同

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:18:40 31 4
gpt4 key购买 nike

这是我们更新 bash 后发生的事情之一(由于 Shellshock 事件)

这是我正在测试的代码:

#!/usr/bin/python2.4
import subprocess, os
p = subprocess.Popen(
cmd,
shell = True,
stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE
)
out, err = p.communicate()

print "out:", out
print "err:", er

首先运行命令:

cmd = "cd /home/me/; pwd; p4 client -o"
out: /home/me/
err:
perforce client that is NOT mine ( some kind of a default template is trying to be used here )

第二个测试,我添加了以下 Python args:

env = os.environ.copy()
# and add "env" variable to the Popen command after "cmd, like:
env = env,

输出:

cmd = "cd /home/me/; pwd; p4 client -o"
out: /home/me/
err:
my perforce client information - as it should.

我的问题是,我似乎无法理解为什么“env = env”在这里很重要。我尝试运行几个命令,例如“export”等,以了解有/没有它之间的区别——但结果是一样的,还检查了“shell”都使用“sh”。所以我不太确定环境的哪一部分导致它无法像示例 #1 那样工作。

我确定它与 Perforce 本身并没有真正的关系,Perforce 可能只是需要一些环境变量,这些环境变量由于这个 bash Shellshock 事件而受到了某种影响。

编辑 - 澄清@5gon12eder 的建议

我尝试在没有“env=env”(这是一个 os.environ.copy() )的情况下查看 ENV,

# 1
# The outouput is wrong ( generic Perforce views )
cd /home/me/; pwd; p4 client -o

# 2 - manually adding P4CONFIG
# The outouput is *correct*
cd /home/me/; pwd; P4CONFIG='.perforce'; p4 client -o


# But the environment variable looks like is there with the correct information ( can't paste it here )
subprocess.call("env") | grepping the script's output P4
> P4CONFIG=...
> P4PORT=...
> P4USER ...

请注意,P4 变量配置了两次:

/etc/profile
/home/me/.bash_profile

编辑 2 - 也用 Perl 复制:

环境忽略 %ENV 中的 P4CONFIG 条目。

#!/usr/bin/perl -w

use strict;
use Data::Dumper;

my $dir = "/home/me/";
my $cmd1 = "cd $dir; p4 client -o";
my $cmd2 = "cd $dir; P4CONFIG='.perforce'; p4 client -o";

# Scenario 1 - does NOT work ! $ENV does have P4CONFIG with a correct value.
`$cmd1`;
# ** still wrong result - generic Perforce views

# Scenario 2 - adding P4CONFIG= to the command:
`$cmd2`;
# Correct result - my .perforce client's views.

# Scenario 3 - Adding to the ENV P4CLIENT ( which does not exists in %ENV )
$ENV{'P4CLIENT'} = "my_client_name";
`$cmd1`; # The one without the P4CONFIG enforcement. - WORK.

编辑 3 - 如果我使用/不使用 >> 和 |

会有区别

实际上,在考虑它时,当我的一个库在上面的子进程(Python)“cmd”示例中有一个“>/dev/null”重定向导致脚本挂起并退出时,引入了整个问题超时,我用“-o file-output”替换它,问题消失了,但后来我陷入了这个问题,所以我打开了这个帖子。

# I already found that adding this row - solving the ENV thing ( not really solving ... but )
$ENV{'P4CONFIG'} = ".perforce";

# Work, I see the excepted output
my $bla = `p4 client -o`;

# Doesn't work, script hangs and Perforce exit with a timeout ( like a P4PORT missing error )
# (I was just trying to remove all the comments-junk )
my $bla = `p4 client -o | grep -v '^#'`;

# Script doesn't hang for example if I just "echo"
my $bla = `echo 'p4 client bla bla' | grep -v '^#'`;

只是想再说一遍,它在 shellshock 之前一切正常(可能是真实的,也可能是巧合),但在 exec() 调用的环境中有些不同......有什么想法吗?

最佳答案

您的代码是否正在修改环境?事情是这样的

os.putenv('VAR', 'VAL')

(可能)直接修改环境但不更新 os.environ

os.environ['VAR'] = 'VAL'

确实如此。来自Python documentation :

Calling putenv() directly does not change os.environ, so it's better to modify os.environ.

If putenv() is not provided, a modified copy of this mapping may be passed to the appropriate process-creation functions to cause child processes to use a modified environment.

在阅读了 os Python 模块和随附的 posixmodule C 模块的有些晦涩的源代码之后,从该文档中变得不太清楚的是,如果 C 库底层平台没有 putenv(3) C 函数,然后在 os.environ 中设置键只会影响 Python 字典,而 os.putenv 是空操作。来自 Lib/os.py:

try:
_putenv = putenv
except NameError:
_putenv = lambda key, value: None
else:
if "putenv" not in __all__:
__all__.append("putenv")

来自Modules/posixmodule.c:

static PyMethodDef posix_methods[] = {
/* Lots and lots of code skipped... */
#ifdef HAVE_PUTENV
{"putenv", posix_putenv, METH_VARARGS, posix_putenv__doc__},
#endif
/* Even more code skipped... */
};

因此,您可以在两种情况下观察到不同的行为,因为 - 令我惊讶的是 - 如果将 env=None 传递给 subprocess.Popen 构造函数,它os.environ 替换为默认值,而是使用 C 标准库中的值。

为子进程设置环境的代码(在Lib/subprocess.py)是

if env is not None:
env_list = [os.fsencode(k) + b'=' + os.fsencode(v)
for k, v in env.items()]
else:
env_list = None # Use execv instead of execve.

并且最近没有变化。并来自 exec(3) 的手册页(强调我的):

The execle() and execvpe() functions allow the caller to specify the environment of the executed program via the argument envp. The envp argument is an array of pointers to null-terminated strings and must be terminated by a null pointer. The other functions take the environment for the new process image from the external variable environ in the calling process.

我进入了Modules/_posixsubprocess.c(用于execv/execve)和Modules/posixmodule 的源代码。 c(对于 putenv)来检查它们是否真的按照描述调用了系统函数,据我所知,它们似乎是这样做的。这两个 C 模块都没有收到似乎与此功能相关的最新更改。

阅读您的问题后,我的第一个想法是,Python 开发人员最终对传递给子进程的环境引入了健全性检查,但他们似乎并没有这样做。很抱歉,如果这不是一个答案,但我认为它可能仍然对其他人有用,可以帮助他们避免深入研究 CPython 源代码。

作为进一步调试的建议,尝试运行

$ python -c "import os; import subprocess; os.putenv('VAR', 'VAL'); subprocess.call('env');" | grep VAR=

和各种变化来追踪正在发生的事情。

脚注:我认为 subprocess.Popen 的行为与其说是一个功能,不如说是一个错误,因为它使 Python 代码在提供或不提供putenv 无缘无故的 C 函数。

关于python - bash shellshock 更新导致脚本行为不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26203311/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com