awk에서 jq를 호출하는 방법은 무엇입니까?

awk에서 jq를 호출하는 방법은 무엇입니까?

기본적으로 다음과 같은 file.log가 있습니다.

blah blah
blah blah
Hello world | {"foo": "bar"}
blah blah
Hello earth | {"foo1": "bar1"}

이제 내 목표는 다음과 같이 원하는 출력을 얻기 위해 몇 가지 쉘 명령을 작성하는 것입니다.

Hello earth | "bar"
Hello earth | "bar1"

현재 내가 가지고 있는 것은 다음과 같습니다.

grep Hello file.log | awk -F "|" '{print $1, system("jq " $2)}'

하지만 jq를 호출하면 다음과 같은 오류가 발생합니다.

jq: error: syntax error, unexpected ':', expecting $end (Unix shell quoting issues?) at <top-level>, line 1:
bin:application   
jq: 1 compile error

나는 이것이 system() 내부에서 내 $12가 모든 따옴표 문자(")를 제거했기 때문에 JQ가 해당 json을 인식하지 못하기 때문이라고 생각합니다. 어떤 제안이 있습니까?

답변1

여기에 몇 가지 질문이 있습니다.

  • system인쇄할 내용을 반환하는 대신 실행한 명령의 종료 값을 반환합니다(모든 것이 잘 되었다면 0). JSON으로 디코딩된 데이터와 그 뒤에 한 줄이 표시됩니다.Hello earth 0
  • JSON 문자열의 큰따옴표는 셸에서 무시됩니다. 실행 중인 결과 명령은 다음과 같습니다 jq {foo: bar}(2개의 인수, JSON은 더 이상 인용되지 않음).
  • $2에 특수 문자가 포함되어 있으면 이를 해석합니다.$
  • 올바른 참조가 있더라도 jq이렇게 호출되지는 않습니다. 첫 번째 인수로 필터가 필요하며(예: " .") 파일이나 표준 입력에서 JSON 입력을 읽어야 합니다.
  • 로그에서 명령을 작성하고 실행하면 보안에 큰 영향을 미칩니다( $2그렇다면 어떨까요 ; rm -rf ~?). 가능하면 피하는 것이 가장 좋습니다.

awk보안 문제를 제외하고 대부분의 경우 작동하는 코드는 다음과 같습니다 .

awk -F "|" '{ printf "%s", $1; system("echo \x27" $2 "\x27 | jq .")}'

그것이 하는 일은 $2작은따옴표( )를 통해 stdin \x27으로 보내는 것입니다 jq.

하지만 문제는 여전히 존재합니다

  • 작은따옴표가 포함 되면 $2전체 명령이 중단됩니다.
  • 대시로 시작 하면 $2(가능성 없음) 옵션으로 해석됩니다 ( 대신 명령을 echo사용할 수 있습니다 ).printfecho
  • 이미 언급된 보안 문제(예: 문자열에 $2포함된 경우)...'; rm -r ~; : ' ...

awk이제 더 나은 코드 가 있습니다

awk -F "|" '{ printf "%s", $1; print $2 | "jq ."; close("jq ."); }'

stdin을 통해 프로세스 $2로 전송되지만 이제 파이프를 사용하므로 쉘은 더 이상 이를 해석하지 않고 위의 모든 문제를 해결합니다. 명령은 모든 줄에서 닫혀야(종료)되어야 하므로 .jqawkjqclose()

답변2

awk를 사용하지 않고 다른 솔루션을 사용하면 됩니다.

비결은 다음과 같습니다.--원본 입력, 파일을 문자열 배열로 읽습니다.

따라서 각 라인에 대해 기호가|여기서 문자열은 잘라내어 json 문자열로 구문 분석됩니다.

jq -j --raw-input  '
    . as $line | 
    if index("|") >= 0  
    then  
      [ .[:index("|")-1] ,.[index("|")+2:] ]  
    else 
      empty
    end | 
   [ .[0] , ( .[1] | fromjson | to_entries | .[0].value ) ] |
   .[0] , " | \"" ,.[1] , "\"\n" '  /tmp/file.log

답변3

xhienne은 좋은 개요를 제공합니다기존 코드의 문제 및 달성하려는 작업에 대한 좋은 대안입니다.

또 다른 옵션은 다음과 같습니다. 호출을 전혀 시도하지 말고 jq스크립트 가 올바른 JSON 출력을 생성하도록 awk하세요 .awk

$ awk -F '|' 'BEGIN { print "[" } $2 != "" { if (t != "") print t ","; t = $2 } END { print t, "]" }' file | jq .
[
  {
    "foo": "bar"
  },
  {
    "foo1": "bar1"
  }
]

코드 awk자체는 발견된 JSON 개체에서 다음 JSON 배열을 생성합니다(질문의 예 제공).

[
 {"foo": "bar"},
 {"foo1": "bar1"} ]

jq이를 통해 스크립트를 유지 관리하고 이해하기 어렵게 만들지 않고도 보다 자유롭게 작업할 수 있습니다 .

스크립트에서 변수를 사용하면 t마지막 JSON 개체 뒤에 후행 쉼표가 표시되지 않습니다.

답변4

간단히 말해서:

jq -r -R '
  select(contains(" | ")) |
  split(" | ") |
  .[0] as $text |
  (.[1] | fromjson | to_entries | .[0].value ) as $json_obj_value |
  "\($text) | \($json_obj_value)"
' yourlogfile.log

완전한 답변

대부분의 사람들은 그것이 얼마나 강력한지 깨닫지 못합니다 jq(그렇다고 말할 수는 있지만 awk).

~처럼Kusaronanda는 그들의 반응에서 신중하게 언급했습니다., 당신의 가장 친한 친구는-R깃발, json 객체 대신 json 문자열로 입력을 한 줄씩 읽습니다. 이렇게 하면 내부 문자열을 자유롭게 처리할 수 jq있으며 전혀 필요하지 않습니다 awk.

문서에서 해당 버전을 설명하는 방법은 다음과 같습니다.1.6:

--raw-input/-R:

입력을 JSON으로 구문 분석하지 마세요. 대신 각 텍스트 줄이 문자열로 필터에 전달됩니다. 와 함께 사용하면 --slurp전체 입력이 하나의 긴 문자열로 필터에 전달됩니다.

원하는 출력을 얻으려면 다음이 필요합니다.-r깃발, 터미널에 json 문자열 대신 기본 문자열을 인쇄합니다.

다시 문서에서

--raw-output/ -r:

이 옵션을 사용하면 필터 결과가 문자열인 경우 인용된 JSON 문자열 형식이 아닌 표준 출력에 직접 기록됩니다. 이는 jq 필터가 JSON 기반이 아닌 시스템과 통신하도록 만드는 데 유용합니다.

따라서 이 문제를 해결한 후 이 문제를 해결하는 방법에는 여러 가지가 있습니다 jq.

~처럼EchoMike444는 이미 보다 필수적인 방식으로 답변했습니다., 저는 좀 더 간소화된 다른 접근 방식을 사용해 보았습니다.

jq -r -R '
  select(contains(" | ")) |
  split(" | ") |
  .[0] as $text |
  (.[1] | fromjson | to_entries | .[0].value ) as $json_obj_value |
  "\($text) | \($json_obj_value)"
' yourlogfile.log

기본적으로 우리는

  1. "|"를 포함하지 않는 줄은 모두 삭제하세요.
  2. 각 행을 두 부분으로 분할
  3. $text읽기 쉽도록 왼쪽 부분을 스테이플로 고정하세요.
  4. 올바른 부분을 json으로 구문 분석하고 첫 번째 값을 가져와 $json_obj_value더 쉽게 읽을 수 있도록 바인딩 에 넣습니다.
  5. 문자열을 인쇄합니다 "$text | $json_obj_value"( \(foo)보간을 수행하는 방법입니다 jq).

가능한 한 컴팩트하게 만들고 싶다면 다음을 사용할 수 있습니다.

jq -Rr 'select(contains(" | "))|split(" | ")|"\(.[0]) | \(.[1]|fromjson|to_entries|.[0].value)"' yourlogfile.log

크기는 작지만 읽기도 더 어렵습니다. 어느 것이 가장 좋은지는 취향과 사용 사례에 따라 다릅니다.

관련 정보