jqを使用してパイプからJSON文字列を生成できますか?

jqを使用してパイプからJSON文字列を生成できますか?

find "$HOME" -maxdepth 1 -type dこのコマンドを使用して、次のような結果が得られたとします。

/home/user/folder1
/home/user/folder2
/home/user/folder3
/home/user/folder4

jqパイプラインで使用し、次のようなさまざまなJSONラインを作成したいと思います。

{ "path": "/home/user/folder1", "type":"directory"}
{ "path": "/home/user/folder2", "type":"directory"}
{ "path": "/home/user/folder3", "type":"directory"}
{ "path": "/home/user/folder4", "type":"directory"}

jqフォルダリストを配列に配置し、ループ内で1つずつ作成することを避けるために、この問題を解決したいと思います。疑似コードでは、アイデアは次のとおりです。

find "$HOME" -maxdepth 1 -type d | jq '.logic-to-create-json-strings'

それを使用できますかjq

答え1

この回答では、ファイル名(またはJSONエンコードするテキスト)が有効なUTF-8であると想定しています。

2つのオプション:

使用しない: 位置引数として pathname をxargs直接呼び出します。jq見つかったパス名を読み取り、式の配列としてアクセスします。各パス名に対してJSONオブジェクトが作成されます。find-exec--args$ARGS.positionaljq

find "$HOME" -maxdepth 1 -type d \
    -exec jq -n -c \
      '$ARGS.positional[] as $path | { path: $path, type: "directory" }' \
      --args {} +

使用法xargs-print0withfind-0withを使用して、xargs見つかったパス名を安全に渡します。パス名が間に渡される方法が異なる点を除いて、式は上記と同じです。findxargsjqfindjq

find "$HOME" -maxdepth 1 -type d -print0 |
xargs -0 jq -n -c \
  '$ARGS.positional[] as $path | { path: $path, type: "directory" }' --args

上記の両方の方法を使用すると、jq見つかったパス名がJSON文字列として表示されるようにエンコードされます。

言い換えれば、効果は同じjqです。

$ARGS.positional[] as $path | { path: $path, type: "directory" }

はい

$ARGS.positional | map({ path: ., type: "directory" })[]

読むワイヤー表示されたオブジェクトのセットを使用すると、jq標準入力ストリームから読み取る次のコマンドを使用できます。

jq -R -c '{ path: ., type: "directory" }'

答え2

JSONは、文字列(UTF-8でエンコードされた文字のシーケンス)から任意のファイルパス(ゼロ以外のバイトのシーケンス)を直接表すことはできません。また参考にしてください出力をfind後処理できません。-print0.

たとえば、ファイルパスはUTF-8でエンコードされ、ISO-8859-1でエンコードされます$'/home/St\xc3\xa9phane\nChazelas/ISO-8859-1/R\xe9sum\xe9'(ここではバイト値を表すためにksh93-style$'...'表記が使用されます)。éStéphaneRésumé

JSONは、一部のエンコーディングを使用しないと、このファイルパスを表すことはできません。たとえば、URIエンコーディングです。

{ "path": "/home/St%C3%A9phane\nChazelas/ISO-8859-1/R%E9sum%E9" }

別のアプローチは、パスをISO-8859-1エンコーディング(またはすべてのバイト値が有効な文字を構成できる単一バイト文字セット)として解釈することです。

{ "path": "/home/Stéphane\nChazelas/ISO-8859-1/Résumé" }

jqURIエンコーディングのいくつかのサポートがありますが、私が知っている限り、UTF-8以外の入力は提供しません。 AFAIK、トランスコーディングもサポートしていません。

GNUシステムでファイルパスがISO-8859-1エンコーディングと見なされる2番目の方法では、次のことができます。

find ~ -type d -print0 |
  iconv -f iso-8859-1 -t utf-8 |
  tr '\0\n' '\n\0' |
  jq -Rc '{"path":sub("\u0000";"\n"),"type":"directory"}'

上記の例では、次のようになります。

{"path":"/home/Stéphane\nChazelas/ISO-8859-1/Résumé.pdf","type":"directory"}

¹iso-8859-1は、コードポイントがUnicodeのコードポイントと一致するため、確実な選択です。したがって、json文字列にU + 00E9文字が含まれている場合、その文字が0xE9バイトに対応することがわかります。代わりに、ASCII以外の文字を表す-aオプションを追加できます。jq\uXXXX

関連情報