我正在尝试编写一个shell脚本,该脚本可以读取json字符串,将其解码为数组并通过数组进行预处理,并使用键/值替换另一个文件中的字符串。
如果这是PHP,那么我会写这样的东西。
$array = json_decode($jsonString, true);
foreach($array as $key => $value)
{
str_replace($key, $value, $rawString);
}
我需要将其转换为Bash脚本。 以下是示例JSON字符串。
{
"login": "lambda",
"id": 37398,
"avatar_url": "https://avatars.githubusercontent.com/u/37398?v=3",
"gravatar_id": "",
"url": "https://api.github.com/users/lambda",
"html_url": "https://github.com/lambda",
"followers_url": "https://api.github.com/users/lambda/followers",
"following_url": "https://api.github.com/users/lambda/following{/other_user}",
"gists_url": "https://api.github.com/users/lambda/gists{/gist_id}",
"starred_url": "https://api.github.com/users/lambda/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/lambda/subscriptions",
"organizations_url": "https://api.github.com/users/lambda/orgs",
"repos_url": "https://api.github.com/users/lambda/repos",
"events_url": "https://api.github.com/users/lambda/events{/privacy}",
"received_events_url": "https://api.github.com/users/lambda/received_events",
"type": "User",
"site_admin": false,
"name": "Brian Campbell",
"company": null,
"blog": null,
"location": null,
"email": null,
"hireable": null,
"bio": null,
"public_repos": 27,
"public_gists": 23,
"followers": 8,
"following": 2,
"created_at": "2008-11-30T21:03:27Z",
"updated_at": "2016-12-21T23:53:11Z"
}
我是这个档案,
Lamba login name is %login%, and avatar url is %avatar_url%
我正在使用jq
jq -c '.[]' /tmp/json | while read i; do
echo $i
done
仅输出值部分。如何循环键并获得价值?
另外,我发现可以使用
返回json字符串的键jq 'keys' /tmp/params
但是,我仍在试图弄清楚如何遍历密钥并返回数据。
答案 0 :(得分:1)
整个事情可以在jq中非常简单(并且非常有效)地完成。
为了便于说明,假设我们已将Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('first_name');
$table->string('last_name');
$table->string('email')->unique();
$table->enum('role', ['coach', 'admin'])->default('coach');
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
Schema::create('teams', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned()->nullable();
$table->string('name')->unique();
$table->string('slug')->unique();
$table->timestamps();
$table->foreign('user_id')->references('id')->on('users');
});
Schema::create('rounds', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
});
Schema::create('round_team', function (Blueprint $table) {
$table->increments('id');
$table->integer('round_id')->unsigned();
$table->integer('team_id')->unisigned();
$table->timestamp('date')->nullable();
$table->timestamps();
$table->foreign('round_id')->references('id')->on('rounds');
$table->foreign('team_id')->references('id')->on('teams');
});
定义为问题中给出的字典对象,并将dictionary
定义为模板字符串:
template
然后可以按如下方式执行所需的插值:
def dictionary: { ...... };
def template:
"Lamba login name is %login%, and avatar url is %avatar_url%";
以上产生:
dictionary
| reduce to_entries[] as $pair (template; gsub("%\($pair.key)%"; $pair.value))
当然还有许多其他方式可以显示字典和模板字符串。
答案 1 :(得分:0)
我假设您的JSON位于infile.json
,而infile.txt
中包含要替换的标记的文字。
这是一个完全不可读的单行代码:
$ sed -f <(jq -r 'to_entries[] | [.key, .value] | @tsv' < infile.json | sed 's~^~s|%~;s~\t~%|~;s~$~|g~') infile.txt
Lamba login name is lambda, and avatar url is https://avatars.githubusercontent.com/u/37398?v=3
现在,要破译它的作用。首先,为了便于阅读,有几个换行符:
sed -f <(
jq -r '
to_entries[] |
[.key, .value] |
@tsv
' < infile.json |
sed '
s~^~s|%~
s~\t~%|~
s~$~|g~
'
) infile.txt
我们基本上使用的是从文件中获取指令的sed命令;我们使用进程替换来生成sed命令而不是实际文件:
jq -r 'to_entries[] | [.key, .value] | @tsv' < infile.json |
sed 's~^~s|%~;s~\t~%|~;s~$~|g~'
使用jq进行一些处理,然后进行一些sed替换。
这是jq命令的作用:
-r
选项生成原始输出(无引号,实际标签而非\t
)使用to_entries
函数将输入JSON对象转换为键值对数组,从而产生
[
{
"key": "login",
"value": "lambda"
},
{
"key": "id",
"value": 37398
},
...
使用[]
获取数组的所有元素:
{
"key": "login",
"value": "lambda"
}
{
"key": "id",
"value": 37398
}
...
使用[.key, .value]
获取每个中包含键/值的数组列表,结果为
[
"login",
"lambda"
]
[
"id",
37398
]
...
最后,使用@tsv
过滤器将键值对作为制表符分隔列表:
login lambda
id 37398
...
现在,我们将它传递给sed,它执行三次替换:
s~^~s|%~
- 将s|%
添加到每行的开头s~\t~%|~
- 将标签替换为%|
s~$~|g~
- 将|g
添加到每行的末尾这为我们提供了一个sed文件,如下所示:
s|%login%|lambda|g
s|%id%|37398|g
s|%avatar_url%|https://avatars.githubusercontent.com/u/37398?v=3|g
请注意,对于这些替换,我们使用~
作为分隔符,对于我们生成的替换命令,我们使用|
- 主要是为了避免遇到包含/
的字符串的问题
如果此sed文件存储为commands.sed
,则整个命令将对应于
sed -f commands.sed infile.txt
<强>说明强>
如果你的shell不支持进程替换,你可以使用sed -f -
从标准输入读取sed:
jq -r 'to_entries[] | [.key, .value] | @tsv' < infile.json |
sed 's~^~s|%~;s~\t~%|~;s~$~|g~' |
sed -f - infile.txt
如果infile.json
包含|
或~
,您必须为sed替换选择不同的分隔符(例如,请参阅this answer有关使用非可打印字符作为分隔符)或甚至执行其他替换以首先删除分隔字符并将它们放回最后(请参阅this和this Q&amp; A)。
\t
时遇到问题。如果是这种情况,则s~\t~%|~
必须将s~'$'\t''~%|~
替换为&#34;拼接&#34;选项卡字符,或者(如果shell不支持ANSI-C引用),即使使用s~'"$(printf '\t')"'~%|~
。