是否可以使用 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避免将文件夹列表放入数组中并在循环中一一创建它们。在伪代码中,这个想法是:

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

可以用 做吗jq

答案1

此答案假设您的文件名(或您希望进行 JSON 编码的任何文本)是有效的 UTF-8。

两种选择:

不使用xargs:直接从with调用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-0withxargs将找到的路径名安全地传递给findto xargs。该表达式与上面的相同,只是路径名在和jq之间传递的方式不同。findjq

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.

例如,文件路径可能是$'/home/St\xc3\xa9phane\nChazelas/ISO-8859-1/R\xe9sum\xe9'(此处使用ksh93-style$'...'表示法来表示字节值),其中éUTF-8 编码为Stéphane,ISO-8859-1 编码为Ré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é" }

jq对 URI 编码有一些支持,但据我所知不能提供非 UTF-8 输入。 AFAIK,它也不支持任何编码转换。

在 GNU 系统上,对于文件路径被认为是 ISO-8859-1 编码的第二种方法,您可以执行以下操作:

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 字节。您可以添加-a选项来代替jq将非 ASCII 字符表示为\uXXXX

相关内容