다음 파일이 있습니다.
$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