【问题标题】:How to parse bash array using Python shlex?如何使用 Python shlex 解析 bash 数组?
【发布时间】:2018-10-15 13:10:32
【问题描述】:

输入:

declare -a ForwardPort=([0]="L *:9102:10.0.1.8:9100 # remote laptop" [1]="L *:9166:8.8.8.8:9100 # google")

期望的输出

我想得到这个输出:

{
    'ForwardPort': [ 
        '"L *:9102:10.0.1.8:9100 # remote laptop"', 
        '"L *:9166:8.8.8.8:9100 # google"'
        ]
}

尝试

我试着用shlex玩了一下,但是数组的解析很糟糕:

import shlex
line='ForwardPort=([0]="L *:9102:10.0.1.8:9100 # remote laptop" [1]="L *:9166:8.8.8.8:9100 # google")'
lex=shlex.shlex(line)
list(lex)
['ForwardPort', '=', '(', '[', '0', ']', '=', '"L *:9102:10.0.1.8:9100 # remote laptop"', '[', '1', ']', '=', '"L *:9166:8.8.8.8:9100 # google"', ')']

问题

有没有办法自动将ForwardPort 的值解析成一个列表?

注意:不要在家里复制,这是一个糟糕的设计决定,导致了这个令人费解的问题:S

【问题讨论】:

  • 你从哪里得到ForwardPort?似乎您正在穿越两种不同的语言。你的“ForwardPort”是 bash 数组格式有什么原因吗?
  • shlex.shlex 是一个词法分析器,它会返回一个由你来解析的标记列表,
  • ...此外,shlex 是为 POSIX sh 定义的。 bash 不是这样的。
  • 如果你只想解析单行字符串,请使用正则表达式,如果你需要上下文/多行解析,我建议使用 pyparsing
  • 退后一步,是什么产生了输入?为什么它不能为 Python(或任何其他语言)生成更有用的东西?

标签: python arrays bash lexical-analysis shlex


【解决方案1】:

你可以用 bash 打印出来:

#!/bin/bash

declare -a ForwardPort=([0]="L *:9102:10.0.1.8:9100 # remote laptop" [1]="L *:9166:8.8.8.8:9100 # google")
res=$(python -c 'import json, sys; print(json.dumps({"ForwardPort": [v for v in sys.argv[1:]]}))' "${ForwardPort[@]}")
echo "$res"

给予:

{"ForwardPort": ["L *:9102:10.0.1.8:9100 # remote laptop", "L *:9166:8.8.8.8:9100 # google"]}

如果你在 python 中将 bash 数组定义为字符串,你可以尝试这个有点粗略的解析:

import re

line='ForwardPort=([0]="L *:9102:10.0.1.8:9100 # remote laptop" [1]="L *:9166:8.8.8.8:9100 # google")'

name, arr = line.split('=(')
arr = arr[:-1]  # removing the trailing ')'
lst = [item for item in re.split('\[\d+\]=', arr) if item]

dct = {name: lst}
print(dct)

【讨论】:

  • 顺便说一句,我序列化 bash 数组以供 Python 解析的常用方法是使用 NUL 分隔符:printf '%s\0' "${array[@]}",然后您的 Python 代码可以在 NUL 上拆分。但就像这个答案一样,这取决于实际调用 bash 来完成这项工作。
  • @hiroprotagonist 我正在从 Python 上下文中加载 bash
  • @ÉdouardLopez:试图在 python 中解析它。这就是你要找的吗?
【解决方案2】:

从 Python 开始,然后从那里启动 bash(实际上与 the answer by hiro 相反,后者从 bash 启动 Python):

import subprocess

print_array_script=r'''
source "$1" || exit
declare -n arrayToPrint=$2 || exit
printf '%s\0' "${arrayToPrint[@]}"
'''

def bashArrayFromConfigFile(scriptName, arrayName):
    return subprocess.Popen(['bash', '-c', print_array_script, '_', scriptName, arrayName],
                            stdout=subprocess.PIPE).communicate()[0].split('\0')[:-1]

print(bashArrayFromConfigFile('file.txt', 'ForwardPort'))

使用如下创建的输入文件进行测试:

cat >file.txt <<'EOF'
declare -a ForwardPort=([0]="L *:9102:10.0.1.8:9100 # remote laptop"
                        [1]="L *:9166:8.8.8.8:9100  # google")
EOF

...正确地作为输出发出:

['L *:9102:10.0.1.8:9100 # remote laptop', 'L *:9166:8.8.8.8:9100  # google']

【讨论】:

    猜你喜欢
    • 2016-02-07
    • 1970-01-01
    • 1970-01-01
    • 2016-03-16
    • 1970-01-01
    • 2014-01-04
    • 1970-01-01
    • 2020-01-06
    • 1970-01-01
    相关资源
    最近更新 更多