파일을 가져와 각 줄을 다른 파일에서 실행되는 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