如何在json文档中的单行shell脚本中创建一个大的shell脚本?

时间:2014-01-07 07:22:08

标签: python linux bash shell subprocess

我正在使用Python和bash shell脚本。我需要从Python脚本执行shell脚本。我成功地能够做到这一点..我需要在JSON字符串中的单行中有一个shell脚本..

以下示例适用于我在JSON文档中制作的简单shell脚本...

import os
import json
import subprocess

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

os.putenv( 'jj3', ' '.join( str(v) for v in jj['pp']  ) )
os.putenv( 'jj4', ' '.join( str(v) for v in jj['sp']  ) )

jsonStr = '{"script":"#!/bin/bash \\n echo Hello World \\n "}'

j = json.loads(jsonStr)

shell_script = j['script']

print "start"
proc = subprocess.Popen(shell_script, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(stdout, stderr) = proc.communicate()
if proc.returncode != 0:
    print "Shell script gave some error"
    print stdout
else:
    print "end"
    print stdout

现在我有一个下面的shell脚本,我需要在JSON文档的一行中表示它,就像我在上面的Hello World用例中所做的那样..

#!/bin/bash
set -e

readonly PRIMARY=/tech01/primary
readonly SECONDARY=/tech02/secondary
readonly LOCATION=(machineA machineB)
readonly MAPPED_LOCATION=/bat/data/snapshot
HOSTNAME=$hostname

dir1=$(ssh -o "StrictHostKeyChecking no" david@${LOCATION[0]} ls -dt1 "$MAPPED_LOCATION"/[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9] | head -n1)
dir2=$(ssh -o "StrictHostKeyChecking no" david@${LOCATION[1]} ls -dt1 "$MAPPED_LOCATION"/[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9] | head -n1)

echo $dir1
echo $dir2

length1=$(ssh -o "StrictHostKeyChecking no" david@${LOCATION[0]} "ls '$dir1' | wc -l")
length2=$(ssh -o "StrictHostKeyChecking no" david@${LOCATION[1]} "ls '$dir2' | wc -l")

echo $length1
echo $length2

if [ "$dir1" = "$dir2" ] && [ "$length1" -gt 0 ] && [ "$length2" -gt 0 ]
then
    rm -rf $PRIMARY/*
    rm -rf $SECONDARY/*
    for el in $primary_partition
    do
        scp david@${LOCATION[0]}:$dir1/weekly_8880_"$el"_5.data $PRIMARY/. || scp david@${LOCATION[1]}:$dir2/weekly_8880_"$el"_5.data $PRIMARY/.
    done
fi

我已将上述shell脚本放在单行JSON文档中,但这不起作用,我总是收到错误

jsonStr = '{"script":"#!/bin/bash \n set -e \n readonly PRIMARY=/tech01/primary \n readonly SECONDARY=/tech02/secondary \n readonly LOCATION=(machineA machineB) \n readonly MAPPED_LOCATION=/bat/data/snapshot \n HOSTNAME=$hostname \n dir1=$(ssh -o \"StrictHostKeyChecking no\" david@${LOCATION[0]} ls -dt1 \"$MAPPED_LOCATION\"/[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9] | head -n1) \n dir2=$(ssh -o \"StrictHostKeyChecking no\" david@${LOCATION[1]} ls -dt1 \"$MAPPED_LOCATION\"/[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9] | head -n1) \n echo $dir1 \n echo $dir2 \n length1=$(ssh -o \"StrictHostKeyChecking no\" david@${LOCATION[0]} \"ls \'$dir1\' | wc -l\") \n length2=$(ssh -o \"StrictHostKeyChecking no\" david@${LOCATION[1]} \"ls \'$dir2\' | wc -l\") \n echo $length1 \n echo $length2 \n if [ \"$dir1\" = \"$dir2\" ] && [ \"$length1\" -gt 0 ] && [ \"$length2\" -gt 0 ] \n then \n rm -rf $PRIMARY/* \n rm -rf $SECONDARY/* \n for el in $primary_partition \n do \n scp david@${LOCATION[0]}:$dir1/t1_weekly_1680_\"$el\"_200003_5.data $PRIMARY/. || scp david@${LOCATION[1]}:$dir2/t1_weekly_1680_\"$el\"_200003_5.data $PRIMARY/. \n done \n fi"}'

这是我得到的错误 -

ValueError: Invalid control character

任何人都可以帮我解决我正在做的事吗?在单行JSON文档中制作上面shell脚本的正确方法是什么?

更新: -

还有另一个转折,我认为值得一提......

我需要将这个单行shell脚本数据存储在Zookeeper节点中。因此对于Hello World shell脚本示例案例,我使用以下代码进行存储。我正在使用Curator库写入Zookeeper。

client.create().creatingParentsIfNeeded().forPath("/be/wf/error1/v1/step1", "{\"description\":\"Hello World 1.\", \"script\":\"#!/bin/bash \\n set -e \\n echo Hello World 1 \\n\"}".getBytes());

然后我让我的Python程序读取Zookeeper节点数据,然后通过从脚本标记中提取来执行shell脚本。

现在我尝试用上面的格式表示答案中提到的相同脚本,然后我的Eclipse开始在字符串上给出编译错误。那么我如何表示上面答案中给出的shell脚本..

我想我真的需要一个JSON,以便我可以在Zookeeper节点中正确存储它,然后我的Python程序可以从节点读取相同的JSON数据并从脚本标记执行shell脚本。

1 个答案:

答案 0 :(得分:3)

首先,考虑一下你是否真的需要JSON。在您的示例代码中,您创建一个JSON字符串,然后立即将其解码为Python dict。直接使用dict会更简单吗?

您当前字符串的问题在于您没有正确转义引号。为避免混淆多级转义,请使用三引号字符串表示shell脚本,并使用json.dumps将dict转换为JSON字符串:

import json
jsonstr = json.dumps({"script": """\
#!/bin/bash
set -e

readonly PRIMARY=/tech01/primary
readonly SECONDARY=/tech02/secondary
readonly LOCATION=(machineA machineB)
readonly MAPPED_LOCATION=/bat/data/snapshot
HOSTNAME=$hostname

dir1=$(ssh -o "StrictHostKeyChecking no" david@${LOCATION[0]} ls -dt1 "$MAPPED_LOCATION"/[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9] | head -n1)
dir2=$(ssh -o "StrictHostKeyChecking no" david@${LOCATION[1]} ls -dt1 "$MAPPED_LOCATION"/[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9] | head -n1)

echo $dir1
echo $dir2

length1=$(ssh -o "StrictHostKeyChecking no" david@${LOCATION[0]} "ls '$dir1' | wc -l")
length2=$(ssh -o "StrictHostKeyChecking no" david@${LOCATION[1]} "ls '$dir2' | wc -l")

echo $length1
echo $length2

if [ "$dir1" = "$dir2" ] && [ "$length1" -gt 0 ] && [ "$length2" -gt 0 ]
then
    rm -rf $PRIMARY/*
    rm -rf $SECONDARY/*
    for el in $primary_partition
    do
        scp david@${LOCATION[0]}:$dir1/weekly_8880_"$el"_5.data $PRIMARY/. || scp david@${LOCATION[1]}:$dir2/weekly_8880_"$el"_5.data $PRIMARY/.
    done
fi"""})

或者,您可以将shell脚本放在自己的文件中,然后打开文件以从中读取字符串。