我的目标是使用Python 2.7.6读取Linux下的文件/etc/os-release
并获取字典。
该文件在Ubuntu中看起来像这样:
NAME="Ubuntu"
VERSION="14.04.2 LTS, Trusty Tahr"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 14.04.2 LTS"
VERSION_ID="14.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
我希望最终得到这样的Python代码会创建的字典结果:
{
'NAME': 'Ubuntu',
'VERSION': '14.04.2 LTS, Trusty Tahr',
'ID': 'ubuntu',
'ID_LIKE': 'debian',
'PRETTY_NAME': 'Ubuntu 14.04.2 LTS',
'VERSION_ID': '14.04',
'HOME_URL': 'http://www.ubuntu.com/',
'SUPPORT_URL': 'http://help.ubuntu.com/',
'BUG_REPORT_URL': 'http://bugs.launchpad.net/ubuntu/',
}
我在Python库中找到了一些解析器,但每个解析器都解析了其他更复杂的语法。我在这里找到了一些示例,但是所有这些都是针对更复杂的语法,并回答了如何编写解析器我只是在寻找已经存在的模块/功能。如果没有,那么,我将只编写自己的代码(所以我不寻找代码示例,除非它是我应该做的)。麻烦的是,我甚至不知道这种语法的名称。虽然我目前的项目是将/etc/os-release
作为字典,但我希望将来需要对类似语法的其他数据执行此操作,因此我的搜索重点是语法,而不是文件。
我认为这个简单的东西应该已经存在。
有趣的是,SO的代码示例显示突出显示,就像这里的Web代码可以解析它而不是Python。
答案 0 :(得分:1)
通过拆分来制作自己的词典:
with open("/etc/os-release") as f:
d = {}
for line in f:
k,v = line.rstrip().split("=")
d[k] = v
print(d)
如果您确实要删除引号,可以使用strip:
with open("/etc/os-release") as f:
d = {}
for line in f:
k,v = line.rstrip().split("=")
# .strip('"') will remove if there or else do nothing
d[k] = v.strip('"')
print(d)
{'VERSION': '14.04.2 LTS, Trusty Tahr', 'NAME': 'Ubuntu', 'HOME_URL': 'http://www.ubuntu.com/', 'ID': 'ubuntu', 'VERSION_ID': '14.04', 'SUPPORT_URL': 'http://help.ubuntu.com/', 'PRETTY_NAME': 'Ubuntu 14.04.2 LTS', 'BUG_REPORT_URL': 'http://bugs.launchpad.net/ubuntu/', 'ID_LIKE': 'debian'}
{'BUG_REPORT_URL': 'http://bugs.launchpad.net/ubuntu/',
'HOME_URL': 'http://www.ubuntu.com/',
'ID': 'ubuntu',
'ID_LIKE': 'debian',
'NAME': 'Ubuntu',
'PRETTY_NAME': 'Ubuntu 14.04.2 LTS',
'SUPPORT_URL': 'http://help.ubuntu.com/',
'VERSION': '14.04.2 LTS, Trusty Tahr',
'VERSION_ID': '14.04'}
答案 1 :(得分:1)
Padraic Cunningham的答案是完美的,我只是跟进回答第二部分(解析那些可以或不可能的引号):如果你想要删除所有引号,只需在Padraic的代码中添加两行。
with open("/etc/os-release") as f:
d = {}
for line in f:
k,v = line.rstrip().split("=")
if v.startswith('"'):
v = v[1:-1]
d[k] = v
print(d)
这是因为我们可以假设如果属性以双引号开头,它将以相同的方式结束。如果你想对单引号也有相同的行为,只需在if中的OR中放入第二个条件。
答案 2 :(得分:1)
如果变量赋值必须包含空格,分号或A-Z,a-z,0-9之外的其他特殊字符,则必须用双引号或单引号括起来。 Shell特殊字符(“$”,引号,反斜杠,反引号)必须使用反斜杠进行转义,遵循shell样式。以“#”开头的行应作为注释忽略。
在为文件编写解析器时,必须考虑上面引用中指定的每个规则。它很复杂,因为它被设计为作为shell脚本执行。实现这意味着实现shell的一部分。
对于引号,除了包含复杂的字符串之外没有任何意义,因此可以忽略。您必须考虑的另一件事是,由'='分割不是100%正确,因为在一行中可能有多个'='。由第一个'='的位置拆分。
答案 3 :(得分:0)
它也可以使用现代(3.5+)python作为简单的dict理解来实现:
has_many :shop_orders
has_many :order_details, through: :shop_orders
这会生成一个这样的字典
{
k.lower(): v.strip('\'"')
for k, v in (
line.strip().split('=', 1)
for line in open('/etc/os-release').read().strip().split('\n')
)
}
或者,我发现一个namedtuple非常有用:
{'name': 'Ubuntu',
'version': '18.04.2 LTS (Bionic Beaver)',
'id': 'ubuntu',
'id_like': 'debian',
'pretty_name': 'Ubuntu 18.04.2 LTS',
'version_id': '18.04',
'home_url': 'https://www.ubuntu.com/',
'support_url': 'https://help.ubuntu.com/',
'bug_report_url': 'https://bugs.launchpad.net/ubuntu/',
'privacy_policy_url': 'https://www.ubuntu.com/legal/terms-and-policies/privacy-policy',
'version_codename': 'bionic',
'ubuntu_codename': 'bionic'}
这会生成一个具有所有可作为属性访问的变量的namedtuple:
from collections import namedtuple
with open('/etc/os-release') as f:
keys, values = zip(*[
(k.lower(), v.strip('\'"'))
for (k, v) in (
line.strip().split('=', 1) for line in f.read().strip().split('\n')
)]
)
r = namedtuple("OSRelease", keys)(*values)