私のconfig.jsonファイルには、次の内容が含まれています。
[{
"host0": "11.11.11.11",
"host1": "22.22.22.22",
"host2": "33.33.33.33",
"host3": "44.44.44.44",
"host4": "55.55.55.55",
"host5": "66.66.66.66"
}]
コマンドラインから起動できる.sh bashスクリプトを作成し、config.jsonファイルを編集して、ホスト0行全体とその値を完全に削除しようとしています。その後、残りの値を「上に移動」する必要があります。つまり、ホスト1をホスト0に、ホスト2をホスト1に、ホスト3をホスト2に、ホスト4をホスト3に変更するなどの名前を意味しますが、その値は同じにする必要があります。最終結果は次のようになります。
[{
"host0": "22.22.22.22",
"host1": "33.33.33.33",
"host2": "44.44.44.44",
"host3": "55.55.55.55",
"host4": "66.66.66.66"
}]
bashスクリプトとjq、またはコマンドラインまたはcronから起動できる他のbashスクリプトを使用してこれを行うにはどうすればよいですか? .shスクリプトにハードコードされています。jq '.host0="22.22.22.22" config.jsonオプションではありません。 config.jsonを読み込み、ホスト1の値をコピーしてホスト0などに貼り付けるスクリプトが必要です。
答え1
次のjq
式は、最上位配列の各要素に変換を適用します(質問の配列には1つの要素しかありません)。変換には、最後に追加されたキー+値の値を最後に追加された要素の値に置き換えることによって、指定されたキーと値から新しい配列を構築することが含まれます。これにより、最初の値が質問から捨てなければならない値であり、最後のキーが質問から捨てなければならないキーである長さの配列n+1
(ここでn
元の配列要素のキーと値の数)が生成されます。質問。 (と書くこともできます)を使用すると、最初と最後の要素を破棄し、キーと値のリストを残します。11.11.11.11
host5
.[1:-1]
del(first,last)
n-1
jq 'map(to_entries | reduce .[] as $a ([{}]; last.value = $a.value | . += [$a]) | .[1:-1] | from_entries)' file
以下は、jq
より読みやすい形式の式です。
map(
to_entries |
reduce .[] as $a (
[{}];
last.value = $a.value |
. += [$a]
) |
del(first, last) |
from_entries
)
次のJSONドキュメントをfile
見ると
[
{
"host0": "11.11.11.11",
"host1": "22.22.22.22",
"host2": "33.33.33.33",
"host3": "44.44.44.44",
"host4": "55.55.55.55",
"host5": "66.66.66.66"
},
{
"server0": "Atlantis",
"server1": "Gotham",
"server2": "Rivendell",
"server3": "Asgard",
"server4": "Hogwarts",
"server5": "Neverland"
}
]
... このjq
コマンドは、次の結果を生成します。
[
{
"host0": "22.22.22.22",
"host1": "33.33.33.33",
"host2": "44.44.44.44",
"host3": "55.55.55.55",
"host4": "66.66.66.66"
},
{
"server0": "Gotham",
"server1": "Rivendell",
"server2": "Asgard",
"server3": "Hogwarts",
"server4": "Neverland"
}
]
キーまたは値文字列は解釈されません。
答え2
jq
このファイルを使用して編集するスクリプト:
#!/bin/sh
set -eu
jq '[.[] | to_entries[1:] | map(.key |= sub("(?<n>\\d+)$";"\((.n|tonumber)-1)")) | from_entries]' "$1" > "$1.tmp"
mv "$1.tmp" "$1"
使用法:
$ cat config.json
[{
"host0": "11.11.11.11",
"host1": "22.22.22.22",
"host2": "33.33.33.33",
"host3": "44.44.44.44",
"host4": "55.55.55.55",
"host5": "66.66.66.66"
}]
$ ./script.sh config.json
$ cat config.json
[
{
"host0": "22.22.22.22",
"host1": "33.33.33.33",
"host2": "44.44.44.44",
"host3": "55.55.55.55",
"host4": "66.66.66.66"
}
]
形式が若干変更されましたが、問題にはなりません。
フォーマットを維持したり、標準のUnixツールを使用したい場合は、awk
notを使用することもできますが、それほどjq
強力ではありません。
awk -F\" 'BEGIN{OFS=FS} $2=="host0"{next} $2~/^host/{$2="host" substr($2,5)-1} 1' "$1" > "$1.tmp"
答え3
もしJavaScript許可される:
それに加えて、構文解析を実行する特別な言語がすでにあるという考えがあります。JSON〜のように組み込みまた〜として知られています
JavaScriptオブジェクト表記法=)
#!/bin/sh
node -e '
function renameKey (obj, oldKey, newKey) {
obj[newKey] = obj[oldKey];
delete obj[oldKey];
}
var j = require("./file.json"); // mandatory ./
delete j[0]["host0"];
let count = Object.keys(j[0]).length;
for (let i = 0; i < count; i++) {
let oldv = "host"+(i+1);
let newv = "host"+i;
renameKey(j[0], oldv, newv)
}
console.log(JSON.stringify(j, null, 4))
'
または
#!/bin/sh
node -p '
JSON.stringify(
require("./file.json")
.map(x => {
let ok;
for (const [k, v] of Object.entries(x)) {
if (ok)
x[ok] = v;
ok = k;
}
delete x[ok];
return x;
})
, null
, 4
)
'
emanuele6のクレジットは次のとおりです。[Eメール保護]。
出力
[
{
"host0": "22.22.22.22",
"host1": "33.33.33.33",
"host2": "44.44.44.44",
"host3": "55.55.55.55",
"host4": "66.66.66.66"
}
]
別の方法は、次の方法を使用してくださいrhino
。
$ dpkg -s rhino
Installed-Size: 55
[...]
Description: JavaScript engine written in Java
Rhino is an implementation of the JavaScript language written
entirely in Java. It is typically embedded into Java applications to
provide scripting to end users.
Original-Maintainer: Debian Java Maintainers <[email protected]>
Homepage: http://www.mozilla.org/rhino/
(ホッケー方式なので本番では使用しないでください)
rhino -e "
function renameKey (obj, oldKey, newKey) {
obj[newKey] = obj[oldKey];
delete obj[oldKey];
}
j = $(< file.json); // shell hack to read file without import fs lib
delete j[0]['host0'];
let count = Object.keys(j[0]).length;
for (let i = 0; i < count; i++) {
let oldv = 'host'+(i+1);
let newv = 'host'+i;
renameKey(j[0], oldv, newv)
}
print(JSON.stringify(j, null, 4))
"
答え4
使用幸せ(以前のPerl_6)
~$ raku -e 'my @json = lines[1..*-2]>>.split(/ <[:,]> /, :skip-empty); put qb[\[\{]; \
@json = join ",\n", ([Z] @json[0..*]>>.[0], @json[1..*]>>.[1])>>.join(":"); \
.put for @json; put qb[\}\]];' file
私はこの答えを書くのを躊躇しましたが、OPにソートエラーが発生したようです。すでに投稿された回答が入力順を維持しているようで幸いですがjq
、少なくともStackOverflow 投稿保証されていないと言いました。 ~からRFC_8259:
> An object is an unordered collection of zero or more name/value
> pairs, where a name is a string and a value is a string, number,
> boolean, null, object, or array.
上記のRakuコードは、テキストに対してリテラルアプローチを取り、最初と最後の角かっこ行を削除しながらテキストを配列lines
として読み込み[1..*-2]
ます(JSONフォーマッタが角かっこ/中括弧を1行ではなく2行に入れる場合は、このインデックスを調整してください) 。各行は<[:,]>
コロンとコンマで構成されるカスタム文字クラスに分割され、空の:skip-empty
要素は削除されます。このように、各@
アレイの位置には、ホストとIPの2つの要素が含まれます。
角かっこ/中括弧はput
別のステートメントとして再利用されます。配列は一緒に「圧縮」され、@json
最初[Z]
の「IP」要素が削除されます(したがって@json[1..*]>>.[1]
最初から削除されません)。項目の要素が不足すると、圧縮は停止します。最後に、コロン、カンマ、改行が再挿入されます。1..
0..
join
入力例:
[{
"host0": "11.11.11.11",
"host1": "22.22.22.22",
"host2": "33.33.33.33",
"host3": "44.44.44.44",
"host4": "55.55.55.55",
"host5": "66.66.66.66"
}]
出力例:
[{
"host0": "22.22.22.22",
"host1": "33.33.33.33",
"host2": "44.44.44.44",
"host3": "55.55.55.55",
"host4": "66.66.66.66"
}]