유연한 패턴 매칭

유연한 패턴 매칭

다음과 같은 파일이 있습니다.

파일 1:

0/28
7200/11
14400/11
21584/28
21600/11
28800/28
36000/11
36000/28
43200/11
43200/28
50400/11
57600/11
79200/28

왼쪽 부분(/ 앞)에는 초 단위의 시간이 있고 오른쪽 부분에는 초 단위의 매개변수 값이 있습니다.

이제 다음과 같은 또 다른 파일이 있습니다.

파일 2:

0 14
0 15
0 20
0 28
7200 11
7200 14
7200 15

이제 두 번째 파일에서 FILE1의 공통 값을 제거하고 싶습니다. 예를 들어 FILE2에서 삭제해야 합니다.

0 28
7200 11

나머지 행은 변경하지 않고 그대로 둡니다.

FILE1의 각 줄에 대해 bash 스크립트에서 for 루프를 사용한 다음 FILE2에서 해당 줄을 검색하고 싶지만 패턴을 인식할 수 없습니다. awk에서 substr을 사용하려고 하면 시간의 숫자가 동일하지 않기 때문에 작동하지 않습니다(0은 1자리, 7200은 4자리).

FILE1을 읽으려면 다음과 같은 작업을 수행합니다.

IFS=$'\n' read -d '' -r -a X < ./FILE1.csv

for 루프를 작성하려면 다음과 같이 하세요.

for x in "${X[@]}"
do
    gawk -i inplace -v var=${x} '{...}' FILE2.csv
done

또한 FILE1을 다음으로 변환하는 것을 고려 중입니다.

0 28
7200 11
14400 11
21584 28
21600 11
28800 28
36000 11
36000 28
43200 11
43200 28
50400 11
57600 11
79200 28

기본적으로 2개의 열이 있지만 위에서 사용한 for 및 var를 사용하여 2개 이상의 열이 있으면 작동하지 않습니다. 두 번째 접근 방식이 더 낫다고 생각하지만 각 열을 개별적으로 처리하는 방법을 모르겠습니다.

편집하다:

FILE1이 다음과 같은 경우:

0 28
7200 11
14400 11
21584 28
21600 11
28800 28
36000 11
36000 28
43200 11
43200 28
50400 11
57600 11
79200 28

FILE2는 다음과 같습니다.

0 14 2 19
0 15 157 67
0 20 28 57
0 28 25 67
7200 11 88 14
7200 14 34 247
7200 15 364 14

답변1

사용 awk:

awk 'NR==FNR { sec[$1, $2]; next } !($1, $2) in sec' FS='/' file1 FS=' ' file2
0 14
0 15
0 20
7200 14
7200 15

이것 FS(에프생산하다에스eerator)는 해당 파일 앞의 각 입력 파일에 대한 필드 구분 기호를 정의합니다.

답변2

마지막 추가 질문에 답하려면:

$ join -v 2 <(sed 's/ /:/' file1) <(sed 's/ /:/' file2) | sed 's/:/ /'
0 14 2 19
0 15 157 67
0 20 28 57
7200 14 34 247
7200 15 364 14

이 답변의 다른 변형과 마찬가지로 join(답을 제공합니다.원래질문), 이렇게 하면 조인 키가 공백이 없는 단일 문자열인지 확인한 다음 두 번째 파일에서 조인 키가 첫 번째 파일의 항목과 일치하지 않는 줄을 선택합니다.

이는 파일이 동일한 방식으로 정렬되어야 한다는 동일한 가정을 만듭니다. join한 번에 두 개의 행만 메모리에 유지되므로 파일 grep의 모든 항목을 메모리에 유지해야 하는 다른 솔루션에 비해 여전히 동일한 이점이 있습니다.


원본 파일 file1file2질문을 사용하여 tr첫 번째 파일을 두 번째 파일과 동일한 형식으로 즉시 변환하고 형식이 변경된 데이터를 일련의 줄로 사용하여 두 번째 파일에서 제거합니다.

$ grep -v -x -F -f <(tr '/' ' ' <file1) file2
0 14
0 15
0 20
7200 14
7200 15

여기서 유틸리티 는 의 변환된 행과 동일한 행을 grep필터링(삭제, 제외)하는 데 사용됩니다 .file2file1

-x옵션은 (일반적인 부분 문자열 일치 대신) 전체 줄 일치를 강제하고 패턴을 정규식 대신 고정 문자열로 -F사용합니다 . grep-f옵션은 유틸리티가 지정된 파일에서 패턴(프로세스 대체)을 읽고 -v해당 행이 일치하도록 일반적인 일치 의미를 반대로 바꾸도록 지시합니다.확실히출력이 일치합니다.

또한 귀하의 질문에 있는 일부 텍스트와 관련이 있습니다.


보다 효율적인 접근 방식은 를 사용하는 것입니다 . 규모가 큰 join경우에는 좋은 생각일 수 있습니다 . file1큰 입력의 경우 를 사용하는 것보다 훨씬 빠를 것으로 예상됩니다 grep.

다음은 두 파일이 모두 동일한 방식으로 정렬되어 있다고 가정하고 두 번째 파일을 첫 번째 파일과 동일한 형식(공백을 슬래시로 대체)으로 변환하여 공백이 없는 줄을 생성합니다. 변환하는 방식에서는 join기본적으로 공백을 구분 기호로 사용하며 공백으로 구분된 첫 번째 필드뿐만 아니라 전체 행을 고려해야 합니다.

$ join -v 2 file1 <(tr ' ' '/' <file2) | tr '/' ' ' 
0 14
0 15
0 20
7200 14
7200 15

그러면 두 데이터세트 간에 관계형 JOIN 작업이 수행되고 두 번째 입력에서 일치하지 않는 행이 join변환된 두 번째 파일로 반환됩니다. 최종 결과로 공백으로 구분된 데이터를 원하므로 후행 슬래시를 공백으로 바꿉니다.

이는 언제든지 메모리에 두 줄 이상의 데이터를 보유하지 않는 반면, 변형은 grep첫 번째 파일의 전체 내용을 메모리에 유지해야 하며 두 번째 파일의 각 줄에 대해 두 번째 파일의 각 줄을 테스트해야 합니다. 라인 파일.

답변3

이 문제는 Shell Loop를 사용하여 해결하겠습니다.

cat FILE2 | tr " " / | \
while read i;do
  cat -n FILE1| grep -w "$i" | awk '{print $1}' | \
  while read j;do
    sed -i "${j}d" FILE1
  done
done

답변4

SUBSEP다음은 퍼지, 필드 반복, 파일 사전 정렬 또는 열/필드 수 사전 설정이 필요하지 않은 솔루션 입니다 .

 mawk -v \_=testfile_001.txt -F/ '
 BEGIN { 
    while(getline<_) {
          __[$!(NF=NF)] 
    }
    _*=close(_)*(FS="^$") } _^($_ in __)' testfile_002.txt 
         
0 14
0 15
0 20
7200 14
7200 15
  • 방금 FS="^$"설정을 구현했습니다.두 번째 파일행 범위 일치를 수행하므로 splitting fields시간이 낭비되므로 훨씬 빠릅니다.

gawk 5.1.1(로고 포함 -c/-P) mawk 1.3.4, mawk 1.9.9.6, 및 작업에 대한 테스트 및 검증을 거쳤습니다.macos nawk

-- The 4Chan Teller

관련 정보