如果需要循环和导入,如何在bash命令中嵌入Python程序?

时间:2018-01-18 21:46:55

标签: python bash

我正在尝试使用Python从某些JSON中提取信息(在我无法安装jq的系统上)。我当前的方法与Why can't use semi-colon before for loop in Python?中描述的语法限制相冲突。如何根据此限制修改此代码仍然有效?

我目前的代码如下所示:

$ SHIFT=$(aws ec2 describe-images --region "$REGION" --filters "Name=tag:Release,Values=$RELEASE_CODE_1.2003.2")
$ echo "$SHIFT" | python -c "import sys, json; for image in json.load(sys.stdin)['Images']: print image['ImageId'];"
  File "<string>", line 1
    import sys, json; for image in json.load(sys.stdin)['Images']: print image['ImageId'];
                        ^

SyntaxError: invalid syntax

由于Python的语法不允许将for循环与带分号的先前命令分开,我如何解决此限制?

1 个答案:

答案 0 :(得分:4)

这里有几个选项:

  • 将您的代码作为多行字符串传递。请注意,为简单起见,"用于分隔Python字符串而不是原始':POSIX兼容机制,用于在单引号字符串中嵌入文字' { {3}}

    extractImageIds() {
      python -c '
    import sys, json
    for image in json.load(sys.stdin)["Images"]:
        print image["ImageId"]
    ' "$@"
    }
    
  • 使用bash的C样式转义字符串语法($'')来嵌入换行符,与$'\n'一样。请注意,前导$至关重要,而且这不适用于/bin/sh。有关详细信息,请参阅is possible, but quite ugly

    extractImageIds() { python -c $'import sys, json\nfor image in json.load(sys.stdin)["Images"]:\n\tprint image["ImageId"]' "$@"; }
    
  • 使用the bash-hackers' wiki on ANSI C-like strings可以避免需要单独的import命令。

    extractImageIds() { python -c 'for image in __import__("json").load(__import__("sys").stdin)["Images"]: print image["ImageId"]' "$@"; }
    
  • 传递stdin上的代码并将输入移动到argv;请注意,这仅在输入不会超出操作系统允许的最大命令行大小时才有效。请考虑以下示例:

    extractImageIds() {
      # capture function's input to a variable
      local input=$(</dev/stdin) || return
      # ...and expand that variable on the Python interpreter's command line
      python - "$input" "$@" <<'EOF'
    import sys, json
    for image in json.loads(sys.argv[1])["Images"]:
        print image["ImageId"]
    EOF
    }
    

    请注意$(</dev/stdin)$(cat)的一种更有效的bash替代方式;由于shell内置支持,它甚至可以在/dev/stdin作为文件不存在的操作系统上运行。

所有这些都经过如下测试:

extractImageIds <<<'{"Images": [{"ImageId": "one"}, {"ImageId": "two"}]}'

要从变量中有效地提供stdin,可以改为运行extractImageIds <<<"$variable"。请注意,包装器中的"$@"元素用于确保sys.argv填充shell函数的参数 - 其中sys.argv未被正在运行的Python代码引用,语法是可选的。