파일에서 특정 다중 패턴만 추출

파일에서 특정 다중 패턴만 추출

다음 파일이 있습니다.

 $less dummyKeyAndValue.txt
   apiKey=key1;some_other_data;term=abc
   apiKey=key2;some_other_data;some_other_data;term=def
   term=pqr;some_other_data;apiKey=key1
   apiKey=key3;some_other_data;term=def

내가 원하는 출력은 다음과 같습니다.

 $less dummyNewFile.txt
   apiKey=key1 term=abc
   apiKey=key2 term=def
   apiKey=key1 term=pqr
   apiKey=key3 term=def

주로 dummyKeyAndValue.txt 파일에서 "apiKey"와 "term"을 추출하려고 합니다. 둘 다 파일에서 서로 다른 순서로 나타날 수 있습니다. 다음 명령을 시도했습니다.

   $cat dummyKeyAndValue.txt | tee >(egrep -o 'apiKey=[a-zA-Z0-9]+')  |   
   egrep -o 'term=[a-zA-Z]+' | less

내가 얻는 결과는 다음과 같습니다.

     term=abc
     term=def
     term=pqr
     term=def

원하는 출력을 얻기 위해 명령을 사용하는 데 도움을 줄 수 있는 사람이 있습니까?

답변1

이 awk 기반 솔루션은 읽기/유지 관리가 더 쉽기 때문에 도움이 될 수 있습니다. awk는 텍스트 파일에서 열과 같은 값을 구문 분석하기 위해 선택하는 도구인 경우가 많습니다.

/tmp$ cat a.awk
{
   keypart=substr($0, index($0, "apiKey=")+7)
   keyvalue=substr(keypart, 1, index(keypart, ";")-1)

   termpart=substr($0, index($0, "term=")+5)
   termvalue=substr(termpart, 1, index(termpart, ";")-1)

# If the attribute is last on the input line there will be no ; to mark the end so use the whole part
   if(keyvalue=="") {keyvalue=keypart}
   if(termvalue=="") {termvalue=termpart}
   printf ("  apikey=%s term=%s\n", keyvalue, termvalue)
}

Awk 스크립트(위에서 a.awk로 명명되었지만 의미 있는 파일 이름을 사용할 수 있음)는 다음과 같이 사용할 수 있습니다.

awk -f a.awk inputfile

보시다시피 각 필드에 대한 if 문을 사용하여 줄 끝에서 끝나는 입력 필드의 경우를 처리했습니다. 이러한 상황을 자동으로 처리하려면 이 스크립트를 다음과 같이 개선하겠습니다.

/tmp$ cat a.awk  
{
   LINE=$0 ";"

   keypart=substr(LINE, index(LINE, "apiKey=")+7)
   keyvalue=substr(keypart, 1, index(keypart, ";")-1)

   termpart=substr(LINE, index(LINE, "term=")+5)
   termvalue=substr(termpart, 1, index(termpart, ";")-1)

   printf ("  apikey=%s term=%s\n", keyvalue, termvalue)
}

더 많은 사례를 추가할수록 이점이 더욱 분명해집니다!

답변2

대안으로, 매우 효과적이지만 약간 복잡한 솔루션

sed 'G;s/;/\n/' | awk -F= '
$1~/apiKey/ {key=$2}
$1~/term/ {term=$2}
/^$/ {printf("  apiKey=%s term=%s\n", key, term)
      key=""
      term=""}'

첫째로 sed는 두 가지 작업을 수행하는 데 사용됩니다. "G" 명령은 각 "레코드 세트" 뒤에 열린 행을 효과적으로 추가하고, 두 번째로 "replace" 명령( s/;/\n/)은 각 레코드 세트를 줄당 하나의 열린 행으로 효과적으로 확장합니다 ;. 각 캐릭터. sed가 생성하는 것은 한 줄에 하나의 키-값 쌍이며, 각 레코드의 끝을 지정하는 빈 줄이 있습니다.

그런 다음 awk는 관심 있는 속성을 찾기 위해 첫 번째 필드만 살펴본 다음 값을 찾기 위해 두 번째 필드를 보면 되므로 index나 substr이 필요하지 않습니다. awk가 "빈 줄"을 만나면 발견된 값을 인쇄합니다. 기능을 복원하려면 각 레코드 끝의 값을 "지우기"하면 됩니다. - 기호를 기준으로 행을 필드로 분할하도록 -F=awk에 지시 하려면 -를 사용하십시오 .=

$1 ~ /.../"첫 번째 필드가 값과 일치할 때"를 의미합니다./.../

그런 다음 변수(키 또는 용어)에 값을 할당합니다.

/^$/"awk가 빈 줄을 만났을 때"를 의미합니다 .

답변3

매우 효율적이지는 않을 수 있지만 "two grep" 접근 방식을 추구하려는 경우 다음을 사용할 수 있습니다 paste.

$ paste <(grep -o 'apiKey=[^;]*' dummyKeyAndValue.txt) <(grep -o 'term=[^;]*' dummyKeyAndValue.txt)
apiKey=key1     term=abc
apiKey=key2     term=def
apiKey=key1     term=pqr
apiKey=key3     term=def

또는 GNU의 KISS 방법을 사용하십시오 sed.

sed -nE -e 's/(apiKey=[^;]*).*(term=[^;]*)/\1 \2/p' \
  -e 's/(term=[^;]*).*(apiKey=[^;]*)/\2 \1/p' dummyKeyAndValue.txt

관련 정보