假设我有file
以下内容:
var1='a random text'
var2='another random text'
var3='a third random text'
eval
我知道,如果我使用如下命令,我会将所有这些变量直接存储在我的 shell 上:
$ eval $(cat file)
这样做,我的 shell 将创建$var1
,$var2
和 以及$var3
它们各自的内容。知道了这一点,我可以手动生成 JSON,如下所示:
$ JSON="{ \"var1\" : \"$var1\", \"var2\" : \"$var2\", \"var3\" : \"$var3\"}"
这将产生一个有效的 JSON:
$ echo $JSON
{ "var1" : "a random text", "var2" : "another random text", "var3" : "a third random text"}
这里的问题是我对键 var1、var2 和 var3 进行了硬编码...在我的例子中,文件可能更大并且存储了更多变量(不仅仅是 var1、var2 和 var3)。我在想是否有一种简单的方法可以使用命令行来实现这一点,就像eval
在 shell 上存储文件变量一样,但不是存储变量,而是生成 JSON 输出。是否可以?我可以使用命令行直接将类似结构的文件转换为 JSON 吗?
我的替代解决方案是开发一个代码(不使用 shell),该代码在该文件中逐个字符地运行,然后我在循环中动态地分离所有内容。但我提出这个问题是因为我想避免使解决方案过于复杂。
答案1
使用组合jo
(来自这里)和jq
(来自这里),而不创建 shell 变量或根本不让 shell 解释该文件:
jo <file |
jq --arg sq "'" '.[] |= ( ltrimstr($sq) | rtrimstr($sq) )'
这首先用于jo
创建 JSON 文档
{
"var1": "'a random text'",
"var2": "'another random text'",
"var3": "'a third random text'"
}
(但在一行上)。它通过将文件中的变量分配解释为键值对来实现此目的。
然后使用该jq
工具删除每个值开头和结尾的单引号。
最终结果是
{
"var1": "a random text",
"var2": "another random text",
"var3": "a third random text"
}
这无法应对值中嵌入的换行符。然而,其他特殊字符将自动由 .json 编码jo
。
答案2
使用zsh
,并假设该文件的语法与 的语法兼容zsh
,该文件不使用 shell 扩展功能(如var1=~/foo
、var2=$var1
、var3=$(uname)
...)并且值是以 UTF-8 编码的文本,您可以这样做:
tokens=( ${(Q)${(zZ[nC])"$(<file)"}} )
根据 shell 语法标记该文件的内容(使用z
参数扩展标志,调整(使用Z[flags]
)以n
将未加引号的换行符视为空白并C
删除 shell 注释)并使用Q
参数扩展标志删除一层引用。
然后你可以将这些标记传递给可以编码 json 的东西(处理控制字符,包括换行符、反斜杠、"
字符等):
perl -CA -MJSON -le '
for (@ARGV) {
if (/(.*?)=(.*)/s) {
$h{$1} = $2;
}
}
print encode_json \%h' -- $tokens
例如,一个file
诸如:
var1='a random text' # comment
var2='another'\'' random text'
var3='a third random text'
name=$'St\u00e9phane Chazelas'
empty=
at=@
more=broken\
down"with 1 \\ backslash"
numstring=1.1
它给:
{"numstring":"1.1","name":"Stéphane Chazelas","empty":"","more":"brokendownwith 1 \\ backslash","var1":"a random text","at":"@","var2":"another' random text","var3":"a third random text"}