grep 후 파이프 명령이 작동하지 않습니다.

grep 후 파이프 명령이 작동하지 않습니다.

파일을 모니터링하고 싶습니다. 그래서 한 줄에 하나의 스크립트를 실행하기 위해 다음 명령을 사용하여 파일을 추적했습니다.

tail -3f logfile.log | grep "action.*add" | sed -u -e "s/^/'/" -e "s/$/'/" | xargs -L 1 -P 5 bash testscript.sh

하지만 스크립트가 실행되지 않는 것 같습니다. grep다음 파이프에는 입력이 제공되지 않는 것으로 나타났습니다 .

내가 시도할 때,

tail -3f logfile.log | grep "action.*add"

효율적인. 그러나 다음 필터(예: sed등)가 주어지면 아래와 같이 작동하지 않습니다.grepxargs

tail -3f /var/tmp/rabbitmq-tracing/logfile.log | grep "action.*add" | grep add 

이런 일이 발생하는 이유와 이 문제를 극복하는 방법을 이해하도록 도와주세요.


편집 1: 기본적으로 다음과 같은 작업이 작동해야 하며 이전에도 작동했습니다. 왜 지금은 작동하지 않는지 혼란 스럽습니다.

tail -f file.txt | grep something | grep something | grep something

편집 2: 첫 번째 grep 이후의 출력 줄은 아래와 같이 json 문자열이 됩니다. 이 줄을 bash 스크립트에 대한 입력으로 사용하고 싶습니다(작은따옴표로 묶음).

{"twNotif": {"originator": "api", "chain": "test", "txId": "08640-0050568a5514", "version": "1.0", "msgType": "api", "twData": {"api": {"hostId": "007bdcc5", "user": "test", "cmdTxt": "100599"}}, "action": "add", "store": "test", "msgTime": 1467280648.971042}}

답변1

--line-buffered스위치 사용grep

tail -3f logfile.log | grep --line-buffered "action.*add" | sed -u -e "s/^/'/" -e "s/$/'/" | xargs -L 1 -P 5 bash testscript.sh

남자 grep에서 :

--line-buffered 출력에 라인 버퍼링을 사용합니다. 이로 인해 성능이 저하될 수 있습니다.


아니면 당신은 사용할 수 있습니다stdbuf 더 읽어보세요

stdbuf를 사용하면 프로그램과 관련된 세 가지 표준 I/O 스트림의 버퍼링 작업을 수정할 수 있습니다. 요약:

다음 구문을 사용하세요.

... | stdbuf -oL grep ... | ...

귀하의 예:

tail -3f logfile.log | stdbuf -oL grep "action.*add" | sed -u -e "s/^/'/" -e "s/$/'/" | xargs -L 1 -P 5 bash testscript.sh

답변2

다른 사람들이 지적했듯이 grep라인 버퍼링이 문제의 명백한 원인입니다.

그러나 현재 수행 중인 작업에는 덜 분명하지만 다른 문제도 있습니다.

sed첫째, 에 입력할 수 있도록 각 출력 줄의 시작과 끝에 아포스트로피를 추가하는 것으로 보입니다 xargs. 이는 필요하지도 않습니다. 옵션 을 xargs사용하여 -d구분 기호로 줄 바꿈을 사용하도록 지시할 수 있습니다. 입력 라인이 없을 때 아무 작업도 수행되지 않도록 하는 것입니다 )xargs -d'\n' -r-rxargs

둘째, 정규식을 사용하여 json 데이터를 구문 분석합니다. 정규식을 사용한 XML 또는 HTML 구문 분석으로 인해 복잡하고 중첩된 구조를 처리하는 것은 신뢰할 수 없고 극도로 어렵거나 심지어 불가능하고 깨지기 쉬우며 갑작스러운 충돌이 발생하기 쉽습니다. XML 또는 HTML을 구문 분석하지 않습니다.정규 표현식 사용. 그것작동하지 않습니다. JSON에도 동일하게 적용됩니다..

대신, 또는 json 데이터에서 필드를 추출하는 것과 jq같은 것을 사용해야 합니다 . jsonpipe예를 들어:

jq -c 'select(.twNotif.action == "add")' file.txt | 
  xargs -d'\n' -r -L 1 -P 5 ./testscript.sh

그냥 파이프하고 싶다면작업 필드 값xargs(큰따옴표 없이) 다음을 수행할 수 있습니다.

jq 'select(.twNotif.action == "add") | .twNotif.action' file.txt | 
  sed -e 's/"//g' | 
  xargs -d'\n' -r -L 1 -P 5 ./testscript.sh

다음과 같은 작업에 사용하기가 jsonpipe더 쉬울 수 있습니다 .awk

jsonpipe < file.txt | 
  awk '$1 == "/twNotif/action" {gsub(/"/,""); print $2}' |
  xargs -d'\n' -r -L 1 -P 5 ./testscript.sh

(여기서의 리디렉션은 와 달리 jqstdin jsonpipe에서만 작동합니다.)

그런데, json 데이터를 , , 등과 jsonpipe같은 행 기반 도구와 함께 사용하기에 적합한 행 기반 형식으로 변환합니다. 예를 들어 :sedgrepawk

$ jsonpipe < file.txt
/   {}
/twNotif    {}
/twNotif/originator "api"
/twNotif/chain  "test"
/twNotif/txId   "08640-0050568a5514"
/twNotif/version    "1.0"
/twNotif/msgType    "api"
/twNotif/twData {}
/twNotif/twData/api {}
/twNotif/twData/api/hostId  "007bdcc5"
/twNotif/twData/api/user    "test"
/twNotif/twData/api/cmdTxt  "100599"
/twNotif/action "add"
/twNotif/store  "test"
/twNotif/msgTime    1467280648.971042

jq특히 json 형식의 출력이 필요하지 않은 경우 보다 사용하기가 더 쉽습니다 .

예를 들어 다음과 같이 쉽게 사용할 수 있습니다 jq.

$ jsonpipe <file.txt | awk '{gsub(/\//,"."); print $1}'
.
.twNotif
.twNotif.originator
.twNotif.chain
.twNotif.txId
.twNotif.version
.twNotif.msgType
.twNotif.twData
.twNotif.twData.api
.twNotif.twData.api.hostId
.twNotif.twData.api.user
.twNotif.twData.api.cmdTxt
.twNotif.action
.twNotif.store
.twNotif.msgTime

답변3

당신이 보고 있는 문제는 아마도 "파이프 버퍼링"일 것입니다. 파이프의 다양한 구성 요소의 출력은 (귀하의 경우 grep) 더 이상 라인 버퍼링이 아니라 블록 버퍼링이며 버퍼는 아마도 다음 구성 요소가 아닌 4K 정도일 것입니다. 즉시 데이터를 참조하십시오. 그것~ 할 것이다데이터가 충분히 들어오면 보세요...

해결책은 약간 고통스럽습니다. 다행히 expect패키지에는 도움이 될 수 있는 명령이 함께 제공됩니다 unbuffer. man unbuffer사용방법에 대한 자세한 내용입니다.

이는 파이프라인의 구성 요소가 터미널과 통신하고 있다고 생각하게 하여 라인을 버퍼링된 상태로 유지함으로써 작동합니다.

관련 정보