Bash 스크립트는 하나의 파일을 입력으로 사용하고 다른 파일에서 awk 명령을 실행합니다.

Bash 스크립트는 하나의 파일을 입력으로 사용하고 다른 파일에서 awk 명령을 실행합니다.

파일을 가져와 각 줄을 다른 파일에서 실행되는 awk 명령 문자열로 실행하는 스크립트를 작성하려고 합니다. 이것이 제가 현재 가지고 있는 것입니다.

#!/bin/bash

FILE=$1
FILE_TO_SEARCH=$2

exec 4> "FILE_TO_SEARCH"

while read -ru 3 LINE; do
    awk -v RS='' -v ORS='\n\n' "$LINE" <&4
done 3< "$FILE"

스크립트를 실행하려고 하면 다음과 같은 결과가 나타납니다.

./bashscript2.sh: line 8: read: read error: 3: Bad file descriptor

예를 들어, 검색할 파일(FILE)의 내용은 다음과 같습니다.

hostAbC
host123
host345
hostMos
hostDef

그런 다음 아래 내용과 유사하지만 더 많은 내용을 포함하는 파일(FILE_TO_SEARCH)에 대해 awk 명령을 실행합니다.

* * * * * * * * *  * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

 id: urn:storageos:Initiator:
    clustername = BLAHBLAHBLAH
    creationTime = java.util.GregorianCalendar[
                time=1490279415811
                2017-03-23 14:30:15 811ms UTC
,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="UTC",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2017,MONTH=2,WEEK_OF_YEAR=12,WEEK_OF_MONTH=4,DAY_OF_MONTH=23,DAY_OF_YEAR=82,DAY_OF_WEEK=5,DAY_OF_WEEK_IN_MONTH=4,AM_PM=1,HOUR=2,HOUR_OF_DAY=14,MINUTE=30,SECOND=15,MILLISECOND=811,ZONE_OFFSET=0,DST_OFFSET=0]
    host = URI: 
    hostname = hostAbC
    inactive = false
    ininode = 01:01:01:01:01:01:01:01
    iniport = 01:01:01:01:01:01:01:01
    internalFlags = 0
    isManualCreation = true
    label = 01:01:01:01:01:01:01:01
    status = OpStatusMap {}
    protocol = FC
    registrationStatus = REGISTERED


 * * * * * * * * *  * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

 id: urn:storageos:Initiator:
    clustername = YADAYADAYADA
    creationTime = java.util.GregorianCalendar[
                time=1485972630239
                2017-02-01 18:10:30 239ms UTC
,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="UTC",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2017,MONTH=1,WEEK_OF_YEAR=5,WEEK_OF_MONTH=1,DAY_OF_MONTH=1,DAY_OF_YEAR=32,DAY_OF_WEEK=4,DAY_OF_WEEK_IN_MONTH=1,AM_PM=1,HOUR=6,HOUR_OF_DAY=18,MINUTE=10,SECOND=30,MILLISECOND=239,ZONE_OFFSET=0,DST_OFFSET=0]
    host = URI: 
    hostname = hostMos
    inactive = false
    ininode = 01:01:01:01:01:01:01:01
    iniport = 01:01:01:01:01:01:01:01
    internalFlags = 0
    isManualCreation = false
    label = 01:01:01:01:01:01:01:01
    status = OpStatusMap {}
    protocol = FC
    registrationStatus = REGISTERED


* * * * * * * * *  * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

그런 다음 awk 명령은 항목 awk -v RS='' -v ORS='\n\n'을 찾아 hostAbC한 공간에서 다른 공간으로 전체 항목을 반환합니다.

나는 그것을 작동시키는 방법을 모른다.

답변1

exec 4> "FILE_TO_SEARCH"

문제는 쓰기용으로만 파일을 열지만(따라서 내용 삭제) 파일 설명자를 읽기용으로 사용하려고 한다는 것입니다.

exec 4< "$FILE_TO_SEARCH"

답변2

내 의견에서 지적했듯이, 우리에게 말하지 않은 것이 없다면 여기서는 stdin 및 stdout 이외의 파일 설명자를 사용할 필요가 없으며 파일 이름을 awk명령에 전달하지 않을 이유도 없는 것 같습니다. 선 .

while read동일한 입력 파일에서 여러 번 실행되도록 쉘 루프를 작성하는 awk것은 원하는 작업을 수행하는 데 매우 나쁜 방법입니다. 아마도 텍스트 파일을 처리하는 가장 나쁜 방법일 것입니다. awk(또는 sed 또는 Perl 등)에서 동일한 작업을 수행하는 것보다 수백 또는 수천 배 느립니다.

다음과 같이 시도해 보세요.

#!/bin/bash

FILE1="$1"
FILE_TO_SEARCH="$2"

awk 'NR==FNR { gsub(/([\\.^$(){}\[\]|*+?])/,"\\\\&",$0);
               if (search == "") {
                 search = $0;
               } else {
                 search = search "|" $0;
               };
               next;
             };

     match($0,search)' "$FILE1" RS='' ORS='\n\n' "$FILE_TO_SEARCH"

(가독성을 위해 줄바꿈과 들여쓰기를 추가했습니다. 이 작업의 awk 부분도 모두 한 줄로 압축했습니다.)

$FILE_TO_SEARCH그러면 의 검색 패턴과 일치하는 모든 레코드 가 인쇄됩니다 $FILE1.

$FILE1기본 &를 사용하여 RS첫 번째 파일( )을 읽고 ORS여기에서 정규식 검색 패턴을 구성합니다. 이 gsub()함수 호출은 검색 패턴에 각 줄을 추가하기 전에 모든 정규식 메타 문자를 백슬래시로 이스케이프하는 데 사용됩니다. 즉, 모든 줄은 고정 문자열로 처리됩니다. 각 줄을 정규식으로 만들려면 아래의 두 번째 버전을 참조하세요.

위의 예에서 $FILE1검색 패턴은 다음과 같습니다.

hostAbC|host123|host345|hostMos|hostDef 

그런 다음 RS=''및 를 사용하여 ORS='\n\n'두 번째 파일( $FILE_TO_SEARCH)을 읽고 검색 패턴과 일치하는 모든 레코드를 인쇄합니다.


$FILE1각 줄을 고정 문자열 대신 정규식으로 해석하려면 다음 버전을 사용할 수 있습니다.

#!/bin/bash

FILE1="$1"
FILE_TO_SEARCH="$2"

awk 'NR==FNR { if (search == "") {
                 search = "(" $0 ")" ;
               } else {
                 search = search "|(" $0 ")";
               };
               next;
             };

     match($0,search)' "$FILE1" RS='' ORS='\n\n' "$FILE_TO_SEARCH"

이 버전의 검색 패턴 예는 다음과 같습니다.

(hostAbC)|(host123)|(host345)|(hostMos)|(hostDef)

이 버전을 사용하면 아무것도 일치하지 않거나 너무 많이 일치하는 깨진 검색 패턴을 쉽게 구축할 수 있습니다. $FILE1에서 리터럴 문자열로 해석하려는 정규식 메타 문자를 이스케이프하려면 백슬래시를 사용해야 합니다. 예를 들어, 텍스트를 일치시키려면 |해당 텍스트가 파일에 있어야 합니다. 그렇지 않으면 정규식 대체 연산자 \|로 해석됩니다 .OR

관련 정보