awk를 통해 목록 파일을 사용하여 기본 파일 편집

awk를 통해 목록 파일을 사용하여 기본 파일 편집

모든 사람. ports.lst와 master.tbl이라는 두 개의 파일이 있습니다.

ports.lst는 다음과 같습니다.

hawaii-P1
hawaii-P2
hawaii-P3
losangeles-P1
losangeles-P3

master.tbl은 다음과 같습니다.

#Site 1 Honolulu
servername HAWAII-A hawaii-P1 InitFileA OutFileA otherfields
servername HAWAII-A hawaii-P2 InitFileA OutFileA otherfields
#servername HAWAII-A hawaii-P3 InitFileA OutFileA otherfields
servername HAWAII-A hawaii-P4 InitFileA OutFileA otherfields

#Site 16 Dallas
servername DALLAS-A dallas-P1 InitFileA OutFileA otherfields
servername DALLAS-A dallas-P2 InitFileA OutFileA otherfields
servername DALLAS-A dallas-P3 InitFileA OutFileA otherfields

#Site 8 L.A.
#servername LOSANGELES-A losangeles-P1 InitFileA OutFileA otherfields
servername LOSANGELES-A losangeles-P2 InitFileA OutFileA otherfields
#servername LOSANGELES-A losangeles-P3 InitFileA OutFileA otherfields

ports.lst에 나열된 모든 포트에 대해 master.tbl 파일을 검색하고 파일이 다음과 같도록 "InitFileA" 및 "OutFileA"를 바꿔야 합니다.

#Site 1 Honolulu
servername HAWAII-A hawaii-P1 InitFileB-hawaii-username-ALPHA-password OutFileB-hawaii-username-ALPHA otherfields
servername HAWAII-A hawaii-P2 InitFileB-hawaii-username-ALPHA-password OutFileB-hawaii-username-ALPHA otherfields
#servername HAWAII-A hawaii-P3 InitFileB-hawaii-username-ALPHA-password OutFileB-hawaii-username-ALPHA otherfields
servername HAWAII-A hawaii-P4 InitFileA OutFileA otherfields

#Site 16 Dallas
servername DALLAS-A dallas-P1 InitFileA OutFileA otherfields
servername DALLAS-A dallas-P2 InitFileA OutFileA otherfields
servername DALLAS-A dallas-P3 InitFileA OutFileA otherfields

#Site 8 L.A.
#servername LOSANGELES-A losangeles-P1 InitFileB-losangeles-username-ALPHA-password OutFileB-losangeles-username-ALPHA otherfields
servername LOSANGELES-A losangeles-P2 InitFileA OutFileA otherfields
#servername LOSANGELES-A losangeles-P3 InitFileB-losangeles-username-ALPHA-password OutFileB-losangeles-username-ALPHA otherfields

그것이 내가 지금 있는 곳이지만 분명히 실패했습니다.

awk 'NR==FNR{z[$0];next}{if ($3 in z && $4 == "InitFileA"){ c=(echo $3| awk -F '-' {print $1});$4="InitFileB-"c"-username-ALPHA-password";$5="OutFileB-"c"-username-ALPHA"}}1' ports.lst master.tbl > output.tbl

나는 또한 다음을 시도했습니다.

awk 'NR==FNR{z[$0];next}{if ($3 in z && $4 == "InitFileA"){ c=$3; sub(/-.*/, "", $c);$4="InitFileB-"c"-username-ALPHA-password";$5="OutFileB-"c"-username-ALPHA"}}1' ports.lst master.tbl > output.tbl

나는 이것에 대해 걱정 해왔다. 여기 누구든지 내가 뭘 잘못하고 있는지에 대한 통찰력을 제공할 수 있습니까?

답변1

작업을 두 라운드로 나누는 올바른 기본 아이디어가 있지만 awk 규칙에서 awk를 호출합니다. 여기서는 읽기를 중단했습니다. 이렇게 간단한 문제에 대한 해결책은 너무 복잡합니다.

다음 awk 조각을 고려해보세요.

awk 'BEGIN {
         RS = "[\t\v\f ]*(\r\n|\n\r|\r|\n)";
         FS = "[\t\v\f ]+"
     }

     FNR==1 {
         file++
     }

     /^#/ {
         next
     }

     file==1 {
         port[$1] = $1
     }

     file>=2 && ($3 in port) {
         base = $3;
         sub(/-[^-]*$/, "", base);
         $4 = "InitFileB-" base "-username-ALPHA-password";
         $5 = "OutFileB-" base "-username-ALPHA";
     }

     file>=2 {
         printf "%s\n", $0
     } ' ports.lst master.tbl

참고: 위의 내용을 모두 한 줄에 작성할 수 있도록 필요한 세미콜론을 추가했습니다.

샘플 입력 파일을 사용하여 위 코드를 실행하면 다음과 같은 결과를 얻을 수 있습니다.

losangeles-P1
losangeles-P3
servername HAWAII-A hawaii-P1 InitFileB-hawaii-username-ALPHA-password OutFileB-hawaii-username-ALPHA otherfields
servername HAWAII-A hawaii-P2 InitFileB-hawaii-username-ALPHA-password OutFileB-hawaii-username-ALPHA otherfields
servername HAWAII-A hawaii-P4 InitFileA OutFileA otherfields

servername DALLAS-A dallas-P1 InitFileA OutFileA otherfields
servername DALLAS-A dallas-P2 InitFileA OutFileA otherfields
servername DALLAS-A dallas-P3 InitFileA OutFileA otherfields

servername LOSANGELES-A losangeles-P2 InitFileA OutFileA otherfields

BEGIN규칙은 파일이 다른 줄 바꿈 인코딩을 사용하는 다른 시스템(예: Windows)에서 전송되는 경우에만 범용 줄 바꿈 지원을 설정합니다.

FNR==1규칙은 file처리 중인 파일을 반영하도록 변수를 업데이트합니다(첫 번째는 1, 두 번째는 2).

/^#/ { next }규칙은 해시 태그로 시작하는 모든 줄을 건너뜁니다. 이는 주석이므로 보관할 필요가 없습니다. /^[\t\v\f ]*$/ { next }출력 파일을 압축하려는 경우 모든 빈 줄을 건너뛰는 규칙을 추가할 수도 있습니다.

file == 1 { port[$1] = $1 }규칙은 첫 번째 파일의 모든 첫 번째 필드를 연관 배열에 추가합니다 port. 할당된 값( = $1)은 중요하지 않으므로 = 0여기서 실제로 사용할 수 있습니다.

규칙 file >= 2 && ($3 in port)은 두 번째 및 모든 후속 파일에 적용되며 세 번째 필드가 연관 배열의 키 중 하나와 일치하는 경우 실행됩니다 port. (값은 중요하지 않고 키만 확인합니다.) 즉, 이 규칙은 세 번째 필드가 포트 목록에 지정된 키 중 하나인 경우에만 적용됩니다.

세 번째 필드는 변수에 복사됩니다 base. 이는 의 키 중 하나와 일치하며 port[]마지막 필드 이후의 모든 항목은 -를 사용하여 삭제됩니다 sub(). 그런 다음 네 번째와 다섯 번째 필드를 수정합니다. awk에는 문자열 연결 연산자가 없습니다. 단지 문자열을 합치는 것뿐입니다. 즉, "foo", 문자열로 변환된 변수 값 , "bar" ("foo" a "bar")로 구성된 문자열입니다 .a

최종 규칙은 (수정될 수 있는) 레코드를 인쇄하지만 반드시 \n개행 문자를 사용해야 합니다. 두 번째 및 후속 파일의 레코드만 사용됩니다.

이제 ports.lst각 사용자 이름과 비밀번호를 포함하도록 위의 내용(세 줄이 변경되었나요?)을 약간 수정하겠습니다. 하지만 전반적인 접근 방식을 볼 수 있기를 바랍니다.

답변2

답을 찾은 것 같습니다. 내 문제는 "c" 변수 근처에 달러 기호를 배치하는 것 같습니다. 즉, 다음과 같이 작동합니다.

awk 'NR==FNR{z[$0];next} { if ($3 in z && $4 == "InitFileA"){ c=$3; sub(/-.*/, "", c);$4="InitFileB-"c"-username-ALPHA-password";$5="OutFileB-"c"-username-ALPHA"}}1' ports.lst master.tbl > output.tbl

이제 그것이 왜 작동하는지 설명할 수 없을 것 같습니다. 나는 말 그대로 지푸라기라도 잡고 절망에 빠졌습니다. 나는 오류가 사라질 때까지 명령 계층을 제거한 다음 각 명령이 작동할 때까지 천천히 명령을 추가하고 수정하는 방법을 사용했습니다.

답변3

단지 명령문을 입력하기에는 충분한 awk 스크립팅을 수행하지 않았지만 "기본" 파일 구조를 사용하고 여러 블록을 갖는 방법을 찾고 있습니다.

개념적 해결

BEGIN
{
#  get it ready ...
}

/^$/
{
# maybe just skip lines
# otherwise potential post processing for #Site XX Name
}

/^#Site/
{
# initialize processing for a new site
}

{
# default block for the site processing 'input'
}

FINISH
{
# 'master' is parsed - now fill in the blanks using 'port'
# i.e, start of second pass to complete the work
}

나는 여기에 awk 명령이 없다는 것을 알고 있습니다. 그러나 awk 전문가가 이것을 awk 솔루션에 대한 일반적인 접근 방식으로 보는지 궁금합니다. 나는 종종 "단일 라인 awk 문"에 빠져 있기 때문에 awk 사용을 거부합니다. 즉, 하나의 명령은 중복 입력 블록이 있는지 여부에 관계없이 모든 라인을 처리합니다.

그리고 이것이 터무니없는 접근 방식으로 판명되더라도 이 의견이 나(그리고 다른 사람들)에게 영감을 주어 awk를 더 잘 사용할 수 있기를 바랍니다. 감사해요!

관련 정보