jq
私の目標は、bashのコマンド出力を使用してJSONオブジェクトを出力することです。find
1行のコマンドでも bash スクリプトでもかまいません。
各出力行にJSONオブジェクトを生成するための次のコマンドがあります。
find ~/ -maxdepth 1 -name "D*" | \
while read line; \
do jq -n \
--arg name "$(basename "$line")" \
--arg path "$line" \
'{name: $name, path: $path}'; \
done
出力は次のとおりです。
{
"name": "Desktop",
"path": "/Users/username/Desktop"
}
{
"name": "Documents",
"path": "/Users/username/Documents"
}
{
"name": "Downloads",
"path": "/Users/username/Downloads"
}
ただし、これらのオブジェクトが配列に存在し、その配列がitems
次のように親オブジェクトの単一キー値になるようにする必要があります。
{"items": [
{
"name": "Desktop",
"path": "/Users/username/Desktop"
},
{
"name": "Documents",
"path": "/Users/username/Documents"
},
{
"name": "Downloads",
"path": "/Users/username/Downloads"
}
]
}
jq
各行の出力文字列に角かっこを追加し('[{name: $name, path: $path}]';
)、角括弧を追加しましたが、配列要素間にカンマは追加しませんでした。
可能な解決策を見つけましたここしかし、各行を繰り返しながら使用する方法がわかりません。
答え1
このjq 1.5
inputs
ストリーミングフィルタトリックは効果があるようです。
... | jq -n '.items |= [inputs]'
前任者。
$ find ~/ -maxdepth 1 -name "D*" |
while read line; do
jq -n --arg name "$(basename "$line")" \
--arg path "$line" \
'{name: $name, path: $path}'
done | jq -n '.items |= [inputs]'
{
"items": [
{
"name": "Downloads",
"path": "/home/steeldriver/Downloads"
},
{
"name": "Desktop",
"path": "/home/steeldriver/Desktop"
},
{
"name": "Documents",
"path": "/home/steeldriver/Documents"
}
]
}
答え2
jq
呼び出しから直接find
結果データを使用して、jq
シェルループなしで最終出力を構築します。
find ~ -maxdepth 1 -name '[[:upper:]]*' \
-exec jq -n --arg path {} '{ name: ($path|sub(".*/"; "")), path: $path }' \; |
jq -n -s '{ items: inputs }'
見つかったパス名ごとにJSONオブジェクトを作成して実行されますjq
。-exec
値の最後のスラッシュまで、パス名のすべての内容を削除し、name
パス名をそのまま値として使用しますpath
。
最後に、jq
データをfind
配列として読み込み、-s
新しいitems
JSONオブジェクトに配列として挿入します。最後のjq
呼び出しは次のように書くこともできますjq -n '{ items: [inputs] }
。
[[:upper:]*
結果の例(代替パターンを使用していることに注意してくださいD*
):-name
find
{
"items": [
{
"name": "Documents",
"path": "/home/myself/Documents"
},
{
"name": "Mail",
"path": "/home/myself/Mail"
},
{
"name": "Work",
"path": "/home/myself/Work"
}
]
}
答え3
プログラミング言語を使うのが気に入らないのはとても簡単です。以下はPHPの例です:
<?php
$m1 = [
'items' => []
];
$a1 = glob('~/D*');
foreach ($a1 as $s1) {
$m1['items'][] = [
'name' => basename($s1),
'path' => $s1
];
}
echo json_encode($m1, JSON_PRETTY_PRINT);