awk 열에서 하나 이상의 일치 항목을 반복합니다.

awk 열에서 하나 이상의 일치 항목을 반복합니다.

문제는 csv 파일의 한 열에 하나 이상의 이메일 주소가 있다는 것입니다. 출력에는 각 이메일 주소에 대해 한 줄이 필요합니다. 각 이메일 주소에 대해 행을 반복하기 위해 이메일 주소에 대해 for 루프를 수행하려면 어떻게 해야 합니까? 정규식을 사용하여 두 번째 열의 모든 이메일 주소를 찾은 다음 배열을 반복하려고 한다고 가정합니다. 하지만 모든 이메일을 배열로 가져오려면 어떻게 해야 합니까?

이것은 간단한 awk 스크립트입니다:

BEGIN {
    FPAT = "([^,]*)|(\"[^\"]+\")"
    OFS=","
}

{ 
    name=substr($1,2,length($1)-2) 
    email=substr($2,2,length($2)-2) 

    print name, email
}

입력하다:

"agrippa","[email protected]"
"elvirka","[email protected]"
"Inofs","[email protected];[email protected]"
"bekbz","[email protected],[email protected]"
"njkzif","[email protected]|[email protected]"
"njycz","[email protected]:[email protected]"
"DanielEdict","[email protected]"
"JosEmbesy","[email protected] , [email protected]"
"Walterdon","[email protected]   ;   [email protected]"
"Kennethlob","[email protected]"
"Ninosh","[email protected]"
"Patrickbam","[email protected]"

원하는 출력:

agrippa,[email protected]
elvirka,[email protected]
Inofs,[email protected]
Inofs,[email protected]
bekbz,[email protected]
bekbz,[email protected]
njkzif,[email protected]
njkzif,[email protected]
njycz,[email protected]
njycz,[email protected]
DanielEdict,[email protected]
JosEmbesy,[email protected]
JosEmbesy,[email protected]
Walterdon,[email protected]
Walterdon,[email protected]
Kennethlob,[email protected]
Ninosh,[email protected]
Patrickbam,[email protected]

실제 데이터에 대해 자세히 알아보면 이는 단지 두 개의 열이 아닙니다. 실제 입력 데이터의 헤더는 다음과 같습니다.

"Created","first name","last name","address1","address2","city","state","zip","country","phone Office","phone Cell","phone Home","company Name","webSite","email","NoEmail","License Type","Issued Date","License Expires"

출력은 단지 두 개의 열이 아니며 이메일은 현재 출력의 최신 항목은 아니지만 필요한 경우 그럴 수 있습니다.

입력 데이터에 대한 또 다른 점은 그것이 CSV 파일이고 모든 데이터에 따옴표가 있다는 것입니다. 단, 데이터가 없으면 따옴표가 없습니다. FPAT는 부분 문자열을 사용하여 제거하는 각 열 주위의 따옴표를 제외하고는 잘 처리하는 것 같습니다.

실제 입력의 예는 다음과 같습니다.

"9/1/2019","Can","Back","77 High Drive","","Chicago","IL","45099","USA","555-555-8521",,,"company name","http://www.yourcomapny.co.uk/","[email protected],[email protected]","","foobar","9/1/2019","9/1/2020"

답변1

GNU awk 사용 FPAT(이미 gawk가 필요하므로 gensub()\s약어 도 사용 [[:space:]]):

$ cat tst.awk
BEGIN {
    FPAT = "([^,]*)|(\"[^\"]+\")"
    OFS=","
}
{
    name = gensub(/^"|"$/,"","g",$1)
    n = split(gensub(/^"|"$/,"","g",$2),emails,/\s*[;,|:]\s*/)
    for (i=1; i<=n; i++) {
        print name, emails[i]
    }
}
$
$ awk -f tst.awk file
agrippa,[email protected]
elvirka,[email protected]
Inofs,[email protected]
Inofs,[email protected]
bekbz,[email protected]
bekbz,[email protected]
njkzif,[email protected]
njkzif,[email protected]
njycz,[email protected]
njycz,[email protected]
DanielEdict,[email protected]
JosEmbesy,[email protected]
JosEmbesy,[email protected]
Walterdon,[email protected]
Walterdon,[email protected]
Kennethlob,[email protected]
Ninosh,[email protected]
Patrickbam,[email protected]

FWIW 저는 일반적으로 이 *sub(/^"|"$/,"",...)방법을 사용하여 CSV 필드에서 가능한 선행/훈련 큰따옴표를 제거합니다. substr()큰따옴표 없이 필드를 나누지 않는 방법에 비해 이점이 있기 때문입니다.

[;,|:]이메일 주소가 손상되었거나 처리를 잊어버린 항목(예: 의 구분 기호 ) 에 대비하여 몇 가지 오류 감지를 추가할 수도 있습니다 .

$ cat tst.awk
BEGIN {
    FPAT = "([^,]*)|(\"[^\"]+\")"
    OFS=","
}
{
    name = gensub(/^"|"$/,"","g",$1)
    n = split(gensub(/^"|"$/,"","g",$2),emails,/\s*[;,|:]\s*/)
    for (i=1; i<=n; i++) {
        email = emails[i]
        if ( gsub(/@/,"&",email) != 1 ) {
            printf "ERROR: too few or too many email addresses in \"%s\"\n", email | "cat>&2"
            exit 1
        }
        print name, email
    }
}

정말로 이메일 주소를 확인하고 싶다면 FWIW 지난 5년 동안 문제가 없었으며 이 정규식의 수정된 버전을 사용해 왔다는 것을 알고 있습니다.http://www.regular-expressions.info/email.html(저는 특별히 [:alpha:] 대신 [a-zA-Z]를 사용했습니다. 왜냐하면 저는 제 로케일에서 그렇게 간주되는 문자만 허용하고 싶기 때문입니다. 애플리케이션에 적합한 문자를 결정하는 것은 여러분의 몫입니다.)

    (email ~ /^[0-9a-zA-Z._%+-]+@[0-9a-zA-Z.-]+\.[a-zA-Z]{2,}$/)

답변2

15개 이상의 열과 7개 열에 대한 괄호 안의 설명을 잘 이해하지 못하지만 주어진 예에서는 다음을 시도해 보십시오.

awk -F, '


        {gsub (/[" ]/,_)                        # remove double quotes and space all over
         D1 = $1                                # save field 1 and
         sub ($1 FS, _)                         # remove it from line
         n  = split ($0, T, /[,;:\|]/)          # split the residual line into array T
         for (i=1; i<=n; i++) print D1, T[i]    # print former $1, and each T element
        }
' OFS=, file
agrippa,[email protected]
elvirka,[email protected]
Inofs,[email protected]
Inofs,[email protected]
.
.
.
Patrickbam,[email protected]

관련 정보