여러 섹션이 있는 파일의 한 섹션에서 문자열 찾기

여러 섹션이 있는 파일의 한 섹션에서 문자열 찾기

sed/awk를 사용하여 다른 문자열에 포함된 문자열을 얻는 방법.

TESTVAR='
{
 icon : "icons/773_l.png",
 id : 80,
 initialState : true,
 isPng : false,
 label : "Imagery",
 opacity : 1,
 requestType : "UUID",
 version : 79
}
,
{
 icon : "thisicon",
 id : 8080,
 initialState : false,
 isPng : true,
 label : "Boundaries",
 opacity : 1,
 requestType : "NothingSpecial",
 version : 8
}

version : 79포함된 개체를 선택해야 합니다 requestType : "UUID". 첫 번째 블록 내부의 모든 항목을 선택하고 버전을 선택한 다음 return 명령을 사용하려면 어떻게 해야 합니까 79? 나는 이것을 한동안 시도해 왔지만 첫 번째 것 사이의 모든 것을 선택하는 방법을 알 수 없습니다 {}. 일단 이것을 갖고 나면 그 다음에는 번호만 알아내면 됩니다 version :.

나는 이것이 효과가 있을 것이라고 생각했지만 그렇지 않았다awk '/\{/{f=1;next}/\}/{f=0}f' test.txt

또한 주문이 보장되지 않습니다. 따라서 "UUID"가 포함된 {모든 항목을 선택해야 합니다 }. 그런 다음 선택version : \([0-9]+\)

이것은 가깝지만 너무 욕심이 많습니다.sed -e 's/{\(.*UUID.*\)}/\1/' test.txt

답변1

내 마음에 가장 먼저 떠오른 것은 sed도 awk도 아니었습니다.

$ tr -d '\n' < file | grep -Po 'requestType : "UUID"\K.*? version : \K[0-9]*'
79

아마도 더 쉽게 할 수 있을 것입니다. 특히 "requestType" 바로 뒤에 "version"이 온다는 것을 보장할 수 있다면 더욱 그렇습니다.

상황을 좀 더 복잡하게 version만들 필요가 없다면 다음 을 수행하세요.requested Type

$ tr -d '\n' < file | grep -Po '{.[^}]*?requestType : "UUID".*?}' | grep -Po 'version : \K[0-9]*'
79

모든 부품과 일치할 수 있는 부품이 더 있으면 인쇄됩니다.

$ cat file
TESTVAR='
{
 icon : "icons/773_l.png",
 id : 80,
 initialState : true,
 isPng : false,
 label : "Imagery",
 opacity : 1,
 version : 79,
 requestType : "UUID"
}
,
{
 icon : "thisicon",
 id : 8080,
 initialState : false,
 isPng : true,
 label : "Boundaries",
 opacity : 1,
 requestType : "NothingSpecial",
 version : 8
}
,
{
 icon : "icons/773_l.png",
 id : 80,
 initialState : true,
 isPng : false,
 label : "Imagery",
 opacity : 1,
 requestType : "UUID",
 version : 87
}
,
{
 icon : "icons/773_l.png",
 id : 80,
 version : 17,
 initialState : true,
 isPng : false,
 label : "Imagery",
 opacity : 1,
 requestType : "UUID"
}
,
{
 icon : "thisicon",
 id : 8080,
 requestType : "NothingSpecial",
 initialState : false,
 label : "Boundaries",
 opacity : 1,
 version : 18,
 isPng : true
}

$ tr -d '\n' < file | grep -Po '{.[^}]*?requestType : "UUID".*?}' | grep -Po 'version : \K[0-9]*'
79
87
17

답변2

awk를 사용하면 레코드 구분 기호를 정의할 수 있으므로 줄 바꿈(각 줄은 레코드임)을 사용하는 대신 "}\n"을 레코드 끝으로 사용하세요.

echo "$TESTVAR" |
gawk -v RS="}\n" '
    /requestType : "UUID"/ && match($0, /version : ([0-9]+)/, m) {print m[1]}
'
79

이는 GNU awk에만 해당되며 match() 함수와 함께 사용됩니다.


불행히도 이것은 유효한 JSON이 아닙니다. 그런 다음 JSON 파서를 사용할 수 있습니다.

jq '(.[] | select(.requestType == "UUID")).version' <<JSON
[
 {
  "icon" : "icons/773_l.png",
  "id" : 80,
  "initialState" : true,
  "isPng" : false,
  "label" : "Imagery",
  "opacity" : 1,
  "requestType" : "UUID",
  "version" : 79
 }
 ,
 {
  "icon" : "thisicon",
  "id" : 8080,
  "initialState" : false,
  "isPng" : true,
  "label" : "Boundaries",
  "opacity" : 1,
  "requestType" : "NothingSpecial",
  "version" : 8
 }
]
JSON

답변3

다음은 순전히 다음을 사용하여 수행하는 한 가지 방법입니다 sed.

$ sed -rn '/\{/{:a;N;/\}/{/requestType : "UUID"/s/.*version : ([0-9]+).*/\1/p;d};ba}' <<< "$TESTVAR"
79
$ 

이것은 다음에서 적응되었습니다.https://stackoverflow.com/a/18046021/2113226귀하의 데이터를 위해.


이것이 자바스크립트 데이터 구조라고 말씀하셨는데, 이를 구문 분석하는 가장 신뢰할 수 있는 방법은 자바스크립트를 사용하는 것이라고 생각합니다. 이를 위해 Node.js를 설치했지만 모든 명령줄 자바스크립트 인터프리터는 다음과 같은 작업을 수행할 수 있어야 한다고 생각합니다.

$ echo "arr=[$TESTVAR]; console.log(arr.filter(function(elem) { return elem.requestType === \"UUID\"; })[0].version)" | node
79
$ 

부인 성명

여기에서 데이터를 안전하게 보관해야 합니다. 자바스크립트에 대해 잘 모르지만, 입력 데이터 문자열을 제대로 제작한다면 코드 인젝션은 전적으로 가능하다고 생각합니다.

관련 정보