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이라고 가정합니다.

두 가지 옵션:

사용되지 않음 : 위치 인수로 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: -print0with find-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로 인코딩된 문자의 시퀀스)에서 임의의 파일 경로(0이 아닌 바이트의 시퀀스)를 직접 나타낼 수 없습니다. 또한 참고하시기 바랍니다출력을 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 인코딩으로 간주되는 두 번째 방법의 경우 다음을 수행할 수 있습니다.

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은 코드 포인트가 유니코드의 코드 포인트와 일치하기 때문에 확실한 선택입니다. 따라서 json 문자열에 U+00E9 문자가 포함되어 있으면 해당 문자가 0xE9 바이트에 해당한다는 것을 알 수 있습니다. 대신 ASCII가 아닌 문자를 나타내는 -a옵션을 추가할 수 있습니다 .jq\uXXXX

관련 정보