如何向subprocess.Popen提供多行命令?

1 投票
3 回答
14249 浏览
提问于 2025-04-18 18:28

我需要通过Python的subprocess.Popen来运行一个多行的dtrace脚本,我尝试了这样做……下面是我在Python中写的代码片段,但这并没有成功,处理这种模板的正确方法是什么呢?

    cmd = "/usr/sbin/dtrace -n '
    #pragma D option quiet
    profile:::profile-1001hz
    /arg0/
    {
            \@pc[arg0] = count();
    }
    dtrace:::END
    {
            printa("%a %\@d\\n", \@pc);
    }'"

    def execute_hotkernel():
    proc = subprocess.Popen(cmd, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
    (output, error) = proc.communicate()
    print output

使用引号并不能把多行命令包裹在cmd里。当我尝试运行时,出现了一个错误:SyntaxError: EOL while scanning string literal

3 个回答

1

这个错误是因为你需要用三个"来表示多行字符串。

 s = """#pragma D option quiet
    profile:::profile-1001hz
    /arg0/
    {
            \@pc[arg0] = count();
    }
    dtrace:::END
    {
            printa("%a %\@d\\n", \@pc);
    }"""

不过我建议你把脚本写到一个文件里,然后用Popen来运行它。

subprocess.Popen(['/usr/sbin/dtrace', 'script_you_have_just_created.td'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)

总之,如果脚本没有变化,就没必要在你的代码里把它保存在一个变量里。

2
arg3 = '''
#pragma D option quiet
profile:::profile-1001hz
/arg0/
{
        \@pc[arg0] = count();
}
dtrace:::END
{
        printa("%a %\@d\\n", \@pc);
}
'''
proc = subprocess.Popen(['/usr/sbin/dtrace', '-n', arg3], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = proc.communicate()

Popen的第一个参数是一个参数列表,除非你设置了shell=True,但这样做不太推荐。

2

这里有几个问题。首先,SyntaxError: EOL while scanning string literal这个错误是因为你试图用一个双引号来创建一个多行字符串,这在Python中是不合法的。你可以使用三个双引号来实现:

cmd = """/usr/sbin/dtrace -n '
#pragma D option quiet
...
"""

第二个问题是,默认情况下,subprocess.Popen需要一个字符串数组,而不是一个用空格分开的命令。如果你想让它接受像你现在这样的一串命令,可以给Popen加上一个参数shell=True。另外,你也可以把命令拆开,把dtrace脚本放在你的多行字符串里:

dtrace_script = """#pragma D option quiet
profile:::profile-1001hz
/arg0/
{
        \@pc[arg0] = count();
}
dtrace:::END
{
        printa("%a %\@d\\n", \@pc);
}
"""
...
subprocess.Popen(['/usr/sbin/dtrace', '-n', dtrace_script], stdout=subprocess.PIPE, stderr=subprocess.PIPE)

撰写回答