【问题标题】:How to convert shell script in one line and execute it from Python subprocess?如何在一行中转换 shell 脚本并从 Python 子进程中执行它?
【发布时间】:2014-04-19 01:57:40
【问题描述】:

我有下面的简单 shell 脚本,我试图将其转换为一行,以便我可以使用子进程从我的 Python 程序中执行它 -

#!/bin/bash
set -e

COUNT=60   #number of 10 second timeouts in 10 minutes
SUM_SYNCS=0
SUM_SYNCS_BEHIND=0
HOSTNAME=$hostname

echo $HOSTNAME

while [[ $COUNT -ge "0" ]]; do

#send the request, put response in variable
DATA=$(wget -O - -q -t 1 http://$HOSTNAME:8080/beat)

#grep $DATA for syncs and syncs_behind
SYNCS=$(echo $DATA | grep -oE 'num_syncs: [0-9]+' | awk '{print $2}')
SYNCS_BEHIND=$(echo $DATA | grep -oE 'num_syncs_behind: [0-9]+' | awk '{print $2}')

echo $SYNCS
echo $SYNCS_BEHIND

#verify conditionals
if [[ $SYNCS -gt "8" && $SYNCS_BEHIND -eq "0" ]]; then exit 0; fi

#decrement the counter
let COUNT-=1

#wait another 10 seconds
sleep 10

done

我将上面的脚本转换成这样的一行 -

jsonStr = {"script": "#!/bin/bash\nset -e\n\nCOUNT=60   #number of 10 second timeouts in 10 minutes\nSUM_SYNCS=0\nSUM_SYNCS_BEHIND=0\nHOSTNAME=$hostname\t\n\necho $HOSTNAME\n\nwhile [[ $COUNT -ge \"0\" ]]; do\n\n#send the request, put response in variable\nDATA=$(wget -O - -q -t 1 http://$HOSTNAME:8080/beat)\n\n#grep $DATA for syncs and syncs_behind\nSYNCS=$(echo $DATA | grep -oE 'num_syncs: [0-9]+' | awk '{print $2}')\nSYNCS_BEHIND=$(echo $DATA | grep -oE 'num_syncs_behind: [0-9]+' | awk '{print $2}')\n\necho $SYNCS\necho $SYNCS_BEHIND\n\n#verify conditionals\nif [[ $SYNCS -gt \"8\" && $SYNCS_BEHIND -eq \"0\" ]]; then exit 0; fi\n\n#decrement the counter\nlet COUNT-=1\n\n#wait another 10 seconds\nsleep 10\n\ndone\n"}

我正在尝试使用 Python 子进程执行此操作,但每次我遇到错误 -

  File "C:\Python27\lib\json\__init__.py", line 326, in loads
    return _default_decoder.decode(s)
  File "C:\Python27\lib\json\decoder.py", line 366, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
TypeError: expected string or buffer

下面是我正在尝试的完整 Python 代码 -

jsonStr = {"script": "#!/bin/bash\nset -e\n\nCOUNT=60   #number of 10 second timeouts in 10 minutes\nSUM_SYNCS=0\nSUM_SYNCS_BEHIND=0\nHOSTNAME=$hostname\t#\n\necho $HOSTNAME\n\nwhile [[ $COUNT -ge \"0\" ]]; do\n\n#send the request, put response in variable\nDATA=$(wget -O - -q -t 1 http://$HOSTNAME:8080/beat)\n\n#grep $DATA for syncs and syncs_behind\nSYNCS=$(echo $DATA | grep -oE 'num_syncs: [0-9]+' | awk '{print $2}')\nSYNCS_BEHIND=$(echo $DATA | grep -oE 'num_syncs_behind: [0-9]+' | awk '{print $2}')\n\necho $SYNCS\necho $SYNCS_BEHIND\n\n#verify conditionals\nif [[ $SYNCS -gt \"8\" && $SYNCS_BEHIND -eq \"0\" ]]; then exit 0; fi\n\n#decrement the counter\nlet COUNT-=1\n\n#wait another 10 seconds\nsleep 10\n\ndone\n"}

j = json.loads(jsonStr)

print "start"
proc = subprocess.Popen(j['script'], shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, executable='/bin/bash')
(stdout, stderr) = proc.communicate()
print stdout
print stderr
print "end" 

我在一行中转换的 shell 脚本有什么问题?有什么想法吗?

注意:我所有其他的 shell 脚本都在工作,它们也在同一个 Python 子进程调用的一个衬里中,只是这有一些问题。

【问题讨论】:

  • 你为什么不使用triple quoted string
  • 也不需要像这样加载,直接执行即可。查看我标记的重复答案。
  • 不知何故,我的所有其他脚本仅在 Python 子进程调用中以这种方式工作,所以我不想像我目前所做的那样更改该调用。因为早些时候,我尝试过你的方式有建议,所以有些脚本运行良好,有些则没有..

标签: python bash shell subprocess


【解决方案1】:

您收到的错误来自json.loads(jsonStr)json.loads 需要 strunicode 而不是 dictjsonStr 已经是 dict 你不需要 json.loads

【讨论】:

  • 我明白了.. 所以如果我这样做 - proc = subprocess.Popen(jsonstr['script'], shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, executable='/bin/bash') 那么它应该可以正常工作吧?我尝试过这种方式,但效果不佳。错误 = string indices must be integers, not str
  • @Webby 删除此行 j = json.loads(jsonStr) 并尝试使用 jsonStr['script']
  • 我已经尝试过了,这是我得到的错误TypeError: string indices must be integers, not str
  • 在 Python 数据结构中使用 bash 语法通常会失败。一些简单的结构(如字符串)可能使用足够相似的语法来表示两者中的相同值,但通常不会。例如,bash 将方括号用于索引可迭代对象以外的目的(这可能是您最近错误的原因)。要么将 bash 脚本捕获为文字字符串(前面的三引号建议,不要忘记前导 r),要么将脚本捕获为文件。尝试在 Python 中使用 bash 语法是没有意义的,也是愚蠢的。
猜你喜欢
  • 1970-01-01
  • 2019-11-21
  • 2011-05-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-18
相关资源
最近更新 更多