【问题标题】:Executing a shell script in Python from the JSON document从 JSON 文档中执行 Python 中的 shell 脚本
【发布时间】:2013-12-28 00:50:25
【问题描述】:

我正在尝试使用子进程模块在 Python 中执行 shell 脚本。

下面是我的shell脚本,称为testing.sh

#!/bin/bash

hello=$jj1

echo $hello

echo $jj1
echo $jj2

for el1 in $jj3
do
    echo "$el1"
done

for el2 in $jj4
do
    echo "$el2"
done

现在我正在尝试在 Python 中执行上面的 shell 脚本,所以我这样做了 -

subprocess.call(['./testing.sh'])

而且效果很好。现在我正在考虑将上述脚本添加到这样的 JSON 文档中,然后执行它 -

json_script = '{"script":"above testing.sh script here"}'
j = json.loads(json_script)
shell_script = j['script']
subprocess.call(shell_script, shell=True)

但每次我尝试时,它都会给我一个错误 -

下面是我的完整 Python 脚本,它在 JSON 文档中包含上述 testing.sh shell 脚本 -

#!/usr/bin/python

import subprocess
import json
import socket
import os

jsonData = '{"pp": [0,3,5,7,9], "sp": [1,2,4,6,8]}'
jj = json.loads(jsonData)

print jj['pp']
print jj['sp']

os.putenv( 'jj1',  'Hello World 1')
os.putenv( 'jj2',  'Hello World 2')
os.putenv( 'jj3', ' '.join( str(v) for v in jj['pp']  ) )
os.putenv( 'jj4', ' '.join( str(v) for v in jj['sp']  ) )

print "start"

jsonDataaa = '{"script":"#!/bin/bash \\n hello=$jj1 \\n echo $hello \\n echo $jj1 \\n echo $jj2 \\n for el1 in $jj3 \\n do \\n echo "$el1" \\n done \\n for el2 in $jj4 \\n do \\n echo "$el2" \\n done"}'
j = json.loads(jsonDataaa)

shell_script = j['script']
print "start"
subprocess.call(shell_script, shell=True)
print "end"

下面是我得到的错误 -

 File "C:\Python27\lib\json\__init__.py", line 338, in loads
    return _default_decoder.decode(s)
  File "C:\Python27\lib\json\decoder.py", line 365, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "C:\Python27\lib\json\decoder.py", line 381, in raw_decode
    obj, end = self.scan_once(s, idx)
ValueError: Expecting , delimiter: line 1 column 113 (char 112) 

我应该得到这样的预期输出 -

[0, 3, 5, 7, 9]
[1, 2, 4, 6, 8]
start
Hello World 1
Hello World 2
0
3
5
7
9
1
2
4
6
8
end

更新:-

如果我有这样的 jsonDataaa

jsonDataaa = '{"script":"#!/bin/bash \\n hello=$jj1 \\n echo $hello \\n echo $jj1 \\n echo $jj2 \\n"}'

然后它工作正常...而且我能够正确执行它..但是如果我的 jsonDataaa 正如我在问题中提到的那样,那么它只会给我一个错误。我在想可能有一些我无法理解的语法错误。

【问题讨论】:

    标签: python json bash shell


    【解决方案1】:

    它给你这个错误是因为你的 json 字符串是无效的。具体来说,它包含未转义的引号。

    如果您将 jsonDataaa 分配替换为:

    jsonDataaa = '{"script":"#!/bin/bash \\n hello=$jj1 \\n echo $hello \\n echo $jj1 \\n echo $jj2 \\n for el1 in $jj3 \\n do \\n echo \\"$el1\\" \\n done \\n for el2 in $jj4 \\n do \\n echo \\"$el2\\" \\n done"}'
    

    【讨论】:

    • 啊愚蠢的错误.. 感谢您指出.. 一个快速的问题。以我目前的方式,我总是只需要以这种格式制作shell脚本吗?这意味着将像这样\\n 添加一个新行,然后是一些命令和转义的双引号等。
    • 还有这个 json 文档有问题吗? jsonDataaa = '{"script":"#!/bin/bash \\n hello=$jj1 \\n echo $hello \\n echo $jj1 \\n echo $jj2 \\n for el1 in $jj3 \\n do \\n echo \\"$el1\\" \\n done \\n for el2 in $jj4 \\n do \\n echo \\"$el2\\" \\n done \\n for i in $( ls ); do \\n echo item: $i \\n done"}'
    • 你不需要 \\n 你可以使用三引号字符串。
    • @JohnZwinck:你能举个例子吗?
    • @SSH 我不知道你为什么要在 python 文件的 json 字符串中嵌入一个 bash 脚本,但如果你从 python repl 做 import jsonjson.dumps({ "script": open("yourfile").read() }) ,你会得到一个正确转义的字符串,可以粘贴到python文件中。
    【解决方案2】:

    这部分不太有意义:

    jsonDataaa = '{"script":"#!/bin/bash \\n hello=$jj1 \\n echo $hello \\n echo $jj1 \\n echo $jj2 \\n for el1 in $jj3 \\n do \\n echo "$el1" \\n done \\n for el2 in $jj4 \\n do \\n echo "$el2" \\n done"}'
    j = json.loads(jsonDataaa)
    
    shell_script = j['script']
    print "start"
    subprocess.call(shell_script, shell=True)
    

    您在这里所做的是将文字字符串作为参数传递给 subprocess.call(),但它需要一个程序名称,而不是程序文本。所以你有几个选择:你可以将shell_script 的内容写入NamedTemporaryFile 并执行它,或者你可以在子进程中启动一个管道bash 并从shell_script 提供它的标准输入作为字符串。我更喜欢后一种方法,您可以在这里获得更多帮助:Python - How do I pass a string into subprocess.Popen (using the stdin argument)?

    P.S.:如果你使用三引号字符串,你可以让你的 JSON 在多行上看起来更好看。

    【讨论】:

    • 如果我有像这样jsonDataaa = '{"script":"#!/bin/bash \\n hello=$jj1 \\n echo $hello \\n echo $jj1 \\n echo $jj2 \\n"}' 的 jsonDataaa,那么它工作正常...而且我能够正确执行它。但是如果我的 jsonDataaa 正如我在问题中提到的那样,那么只有它给我一个错误。我在想可能有一些我无法理解的语法错误..
    • 我不明白。也许您可以在问题中并排地对可以工作和不工作的确切最小 Python 脚本进行清晰、详细的比较。并将其更改为使用三引号块字符串,以便我们可以阅读它。
    • 查看已编辑的问题。如果您将问题中的 jsonDataaa 字符串替换为我更新的 jsonDataaa 字符串,则整个程序将被执行,但使用原始 jsonDataaa 字符串,它不能正常工作。所以我的 json 文档中有一些语法错误
    • 实际上,'shell=True' 第一个参数是一个完整的命令行,将被传递到/bin/sh。例如,它可以是“(rm *.h; ls|grep spider>arach.txt)”。
    • 所以我现在认为我的回答不应该有帮助,而且我不确定为什么不同的 jsonDataaa 会有所不同。也许我们缺少的原始格式存在错误;尝试插入 open("script_test","w").write(shell_script) 看看会发生什么。
    【解决方案3】:

    你也可以这样做:

    subprocess.call(["/bin/sh", "-c", shell_script])
    

    您将整个脚本作为单个命令行参数传递给 sh。 即使 shell_script 中有换行符,这也应该有效;但如果它超过一定的大小(16K 字节?类似的东西),它将不适合命令行。

    编辑 - 通过使用 subprocess.call(shell_script, shell=True) 它实际上与我所建议的相同,或多或少(也许其他选项的效果可能不同)。所以现在我猜测 \n 等的引用可能不正确,正如你所暗示的 - 请参阅下面的 cmets。

    【讨论】:

    • 所以您是说,在您的示例中,我不需要将换行符添加为\\n,然后再添加一些命令?我可以直接将它们放在一行中,中间有一个空格,它应该可以吗?
    • 等等 - 不太确定,看看其他答案。
    • 实际上,我在这里依赖换行符实际上是换行符(不是 \ 实际的 n,而是实际的换行符),这在我的示例中没问题(因为它仍然显示为 / bin/sh)
    • 所以,我认为 JsonDataa 的格式(通过 2 级引用)可能是问题所在。遵循使用 tripe-quotes 的建议,以及我关于将字符串写入文件以查看实际内容的建议(或者只是 'print shell_script' 和 print repr(shell_script) 并仔细检查)
    猜你喜欢
    • 2011-05-21
    • 2019-12-29
    • 2015-01-09
    • 2019-12-11
    • 1970-01-01
    • 2014-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多