쉘 스크립트를 사용하여 텍스트 파일 처리 및 명령 생성

쉘 스크립트를 사용하여 텍스트 파일 처리 및 명령 생성

아래와 같이 서버와 도메인 이름이 포함된 파일이 있습니다.

이름.txt:

ABCDomain ContractABCServer_1
ABCDomain ABC_server1
LinkDomain CoreLinkServer_1
TADDomain TADServer_1

(다른 파일에 대해 정렬 및 고유 작업을 수행한 후 위 파일을 얻었습니다.) --- 추가 정보

위 파일에서 값을 추출하여 xyz 명령(서버를 다시 시작하는 데 사용됨)에 다음 형식의 인수로 전달해야 합니다.

산출:

"ABCDomain(server:ContractABCServer_1,server:ABC_server1)","LinkDomain(server:CoreLinkServer_1)","TADDomain(TADServer_1)"

아래에 설명된 논리를 사용하고 있지만 각 컬렉션의 도메인 이름이 한 번만 나타나야 하므로 원하는 출력이 제공되지 않습니다. 나 역시 같은 선을 유지하는 데 어려움을 겪는다.

- - - - - -시작- - -

    DOMAIN=''

IFS=' '
while read line
do
        DOMAIN=$(echo "$line" | awk -F " " '{print $1}')

        for word in $line
        do
                if [[ "$word" == "$DOMAIN" ]]; then
                        Server=$(echo "$line" | awk -F " " '{print $2}' )
                        echo -n "(server:$ServerName"
                fi

        done

done < Names.txt

답변1

{
    if (dom[$1]) 
        dom[$1]=dom[$1]","$2
    else 
        dom[$1]=$2
} 

END {
    ORS=",";
    for (d in dom)
        if (d)
            print ("\""d"(server:"dom[d]")""\"")
}

빠르고 더러운 awk 솔루션은 다음과 같습니다. Something.awk로 저장하고 다음을 실행하세요.

awk -f something.awk Names.txt 

귀하의 질문에 대한 답변을 위한 빠른 수정논평:

{ dom[$1]=dom[$1] ? dom[$1]",server:"$2 : "server:"$2 }

END {
    for (d in dom)
        if (d) {
            out && out = out","
            out = out"\""d"("dom[d]")""\""
        }
        print out
}

답변2

쉼표로 구분된 문자열을 직접 결합 awk하고 끝에 조합을 인쇄할 수 있습니다.

  $1 == "ABCDomain"  {d = (d == "") ? $2 : d "," $2; next} 
  $1 == "LinkDomain" {l = (l == "") ? $2 : l "," $2; next} 
  $1 == "TADDomain"  {t = (t == "") ? $2 : t "," $2; next} 

  END {
    printf("\"ABCDomain(server:%s)\",\"LinkDomain(server:%s)\",\"TADDomain(%s)\"\n", d, l, t)
  }

전임자.

$ awk '
  $1 == "ABCDomain"  {d = (d == "") ? $2 : d "," $2; next} 
  $1 == "LinkDomain" {l = (l == "") ? $2 : l "," $2; next} 
  $1 == "TADDomain"  {t = (t == "") ? $2 : t "," $2; next} 

  END {
    printf("\"ABCDomain(server:%s)\",\"LinkDomain(server:%s)\",\"TADDomain(%s)\"\n", d, l, t)
  }' Names.txt
"ABCDomain(server:ContractABCServer_1,ABC_server1)","LinkDomain(server:CoreLinkServer_1)","TADDomain(TADServer_1)"

답변3

이 코드를 사용할 수 있습니다. /tmp해당 폴더에 디렉터리가 생성된 domains후 삭제 되므로 실행하기 전에 코드를 읽어 보십시오.

 DOMAIN=''

    IFS=' '
    declare -A domain
    mkdir /tmp/domains
    while read line
    do
            DOMAIN=$(echo $line | awk  '{print $1}')
            SERVER=$(echo $line | awk '{print $2}' )
            echo "$SERVER," >> /tmp/domains/$DOMAIN
            domain[$DOMAIN]=1
    done < Names.txt

    sed -ir "$ s/.,$//" /tmp/domains/*

    for i in "${!domain[@]}"; do
             echo -n "$i(server:";
             while read line ; do
                 echo -n "$line" ;
             done < /tmp/domains/$i
             echo ")"
    done
    rm -rf /tmp/domains

그러면 각 도메인 파일 이름에 포함된 서버 목록이 포함되도록 다음 데이터가 포함된 /tmp 폴더에 폴더가 생성됩니다.

$ ls -lhtr /tmp/domains/
total 12K
-rw-rw-r-- 1 arushirai arushirai 11 Jun 19 17:54 TADDomain
-rw-rw-r-- 1 arushirai arushirai 16 Jun 19 17:54 LinkDomain
-rw-rw-r-- 1 arushirai arushirai 32 Jun 19 17:54 ABCDomain

$ cat /tmp/domains/ABCDomain 
ContractABCServer_1,
ABC_server
$ cat /tmp/domains/LinkDomain 
CoreLinkServer_
$ cat /tmp/domains/TADDomain 
TADServer_

답변4

(올바른 출력 형식으로 업데이트됨)

사용 awk:

BEGIN { OFS = "," }

{ servers[$1] = (servers[$1] == "" ? "server:" $2 : servers[$1] "," "server:" $2 ) }

END {
    $0 = ""
    for (domain in servers)
        $(++n) = sprintf("\"%s(%s)\"", domain, servers[domain])

    print
}

그러면 입력 파일을 구문 분석할 때 기본 블록의 특정 도메인에 쉼표로 구분된 문자열로 서버가 추가됩니다. 이는 servers특정 도메인에 대한 서버를 보유하는 배열을 수정하여 수행됩니다(도메인은 배열의 키입니다).

END블록에서는 배열의 모든 키/필드를 반복하고 servers지정된 형식으로 출력 레코드를 생성합니다.

제공된 데이터에 대해 실행:

$ awk -f script.awk names.txt
"TADDomain(server:TADServer_1)","ABCDomain(server:ContractABCServer_1,server:ABC_server1)","LinkDomain(server:CoreLinkServer_1)"

기본적으로 동등한 bash스크립트( bash연관 배열의 경우 4.3+ 필요):

declare -A servers

while read domain server; do
    servers[$domain]+="${servers[$domain]:+,}server:$server"
done <names.txt

for domain in "${!servers[@]}"; do
    out+="${out:+,}\"$domain(${servers[$domain]})\""
done

printf '%s\n' "$out"

...하지만 "를 참조하세요"쉘 루프를 사용하여 텍스트를 처리하는 것이 왜 나쁜 습관으로 간주됩니까?".

관련 정보