패턴으로 구분된 연속 행 그룹을 결합하는 기술

패턴으로 구분된 연속 행 그룹을 결합하는 기술

다음과 같은 목록이 있습니다.

$$<002L_tbfl
Putative transcription factor 001R;
GO:0006355
GO:0046782
GO:0006351
IPR007031
$$<002L_FRG3G
Uncharacterized protein 002L;
GO:0033644
GO:0016021
IPR004251

나는 각각이 새로운 줄을 시작하고 다시 나타날 $$<때까지 같은 줄(탭으로 구분)에 다음 항목을 갖기를 원합니다. $$<이와 같이:

$$<002L_tbfl    Putative transcription factor 001R; GO:0006355  GO:0046782  GO:0006351  IPR007031
$$<002L_FRG3G   Uncharacterized protein 002L;   GO:0033644  GO:0016021  IPR004251

지금까지 나의 접근 방식은 다음과 같습니다.

tr '\n' '\t'   < stage1 > stage2
sed 's/$$</\n/g' stage2 > stage3

문제는 위의 방법이 작은 파일에서는 완벽하게 작동하지만 4GB 파일에서는 작동하는 것처럼 보인 다음 짧은 시간 동안 오류나 메시지 없이 빈 파일을 반환한다는 것입니다.
나도 시도해 보았지만 tr '$$<' '\n'작동하지 않습니다. 이상한 파일이 생성됩니다.

답변1

수행 방법은 다음과 같습니다 sed.

sed -n '/$$</! H; /$$</{x; s/\n/\t/gp}; ${x; s/\n/\t/gp}' stage1 > stage3

부분으로 나누어져 있습니다:

  • sed -n기본 출력(즉, 처리된 입력)이 인쇄되지 않고 p명령을 받은 경우에만 인쇄됨을 의미합니다.
  • /$$</! H선이 보일 때를 의미합니다.아니요포함되어 있으면 $$<"에 추가하세요.시간이전 공간"(예: 준비 영역). 이는 !일반적인 논리를 뒤집어 "이 조건을 충족하지 않는 행에 대해 이 작업을 수행"을 의미합니다. $$<행 중간에서 발생하는 일을 무시해야 하는 경우 이 설정을 변경합니다(및 ( 예를 들어 줄 앞에 개행을 삽입하는 등 줄 중간을 다르게 처리 /^$$</해야 하는 경우 이를 기록하도록 질문을 편집하세요. )$$<

    예약된 공간(예약된 공간)에 이미 콘텐츠가 있는 경우 예약된 공간에 줄을 추가하는 경우 sed그 사이에 줄바꿈 문자를 삽입하면 예약된 공간에 다음과 같은 텍스트가 작성됩니다.

    $$<002L_tbfl newline추정 전사 인자 001R newline이동: 0006355…

    공간을 "패턴 공간"(일반 작업 라인 버퍼)으로 예약 일반적으로 말하면끝에는 명시적인 개행 문자가 없습니다(암시적입니다). 물론, 공백 내에 명시적으로 개행 문자를 삽입할 수 있습니다.

  • /$$</{…}중괄호로 묶인 명령이 포함된 행에서 실행됨을 나타냅니다 $$<.

    • xe를 의미한다엑스예약된 공간과 패턴 공간의 내용을 변경합니다.
    • s/\n/\t/gp의미 - 글쎄요, 당연한 거죠, 그렇죠? — 이는 (패턴 공간에서) 개행 문자를 탭으로 바꾸는 것을 의미합니다. G전 세계적으로 그리고결과를 인쇄합니다.

    이 명령이 입력의 첫 번째 라인( 포함 $$<) 을 읽으면 x해당 라인( $$<002L_tbfl)을 패턴 공간에서 예약된 공간으로 이동하고 예약된 공간의 이전 내용을 패턴 공간으로 이동합니다. 그러나 예약된 공간의 초기 내용은 아무것도 없기 때문에 명령이 적용되지 않습니다 s. 나중에 (예를 들어 7번째 줄에서) 볼 때 $$<(위에 표시된 대로) 새 줄이 포함된 텍스트를 패턴 공간으로 가져오고 (위와 같이) 모든 줄 바꿈을 탭으로 바꾸고 결과를 인쇄합니다.

  • ${…}입력 끝에 도달하면 중괄호로 묶인 명령이 실행됨을 나타냅니다. 이는 $$<예약된 공간에서 마지막 행(즉, 마지막 행)을 지우기 위해 를 볼 때 실행한 것과 동일한 명령입니다 .

경고: POSIX에서의 작동이 보장되지는 않습니다 sed. 나는 그것을 GNU에서 테스트했습니다 sed.

답변2

$ cat ip.txt 
$$<002L_tbfl
Putative transcription factor 001R;
GO:0006355
GO:0046782
GO:0006351
IPR007031
$$<002L_FRG3G
Uncharacterized protein 002L;
GO:0033644
GO:0016021
IPR004251

$ perl -ne 'chomp if !eof; if($. > 1){print /\$\$</ ? "\n" : "\t"} print' ip.txt 
$$<002L_tbfl    Putative transcription factor 001R; GO:0006355  GO:0046782  GO:0006351  IPR007031
$$<002L_FRG3G   Uncharacterized protein 002L;   GO:0033644  GO:0016021  IPR004251
  • chomp if !eof파일의 마지막 줄을 제외한 모든 입력 줄에서 개행을 제거합니다.
  • if($. > 1)1보다 큰 줄 번호를 입력하세요.
  • print /\$\$</ ? "\n" : "\t"줄이 일치하면 개행을 추가하고 $$<, 그렇지 않으면 탭하세요.
  • print입력 라인 인쇄

답변3

아마도 32비트 제한이 있어서 스트리밍만 가능합니다. 당신은 awk다음과 같은 것을 사용할 수 있습니다

awk 'NR==1 {printf "%s",$0; next;} $1~/^\$\$</ {printf "\n%s",$0; next;} {printf "\t%s",$0;}' < file

$$<이렇게 하면 첫 번째 줄바꿈으로 시작하는 줄(첫 번째 줄 이후)을 제외하고 줄바꿈 없이 모든 입력 줄이 연속적으로 인쇄됩니다 .

어쩌면 END 섹션이 필요한 마지막 개행 문자를 원할 수도 있습니다. 이러한 변경 사항을 확인하세요 man awk.

답변4

Ubuntu 12에서 Mawk 및 Gawk 3.x와 함께 작동하며 RS정규식을 지원합니다.

$ awk 'BEGIN { RS="\\$\\$<"; FS="\n"; OFS="\t" } NF && $1="$$<"$1' data

산출:

$$<002L_tbfl    Putative transcription factor 001R; GO:0006355  GO:0046782  GO:0006351  IPR007031   
$$<002L_FRG3G   Uncharacterized protein 002L;   GO:0033644  GO:0016021  IPR004251

우리는 단순히 $$<개행 문자를 레코드 구분 기호로 사용하고 개행 문자를 필드 구분 기호로 사용합니다.

이는 다음을 의미합니다.

  • 입력이 레코드 구분 기호로 시작하므로 빈 레코드를 얻습니다. 다음 조건을 사용하여 이 문제를 제거합니다 NF. 필드 수는 0이 아니어야 합니다.
  • $$<입력에서 제거되었습니다. 우리는 그것을 다시 넣었습니다 $1.

중간에 탭이 있는 필드를 인쇄하려면 탭을 출력 필드 구분 기호( OFS)로 설정합니다. { print }모드의 기본 동작이므로 무시합니다.

우리가 수정했다는 사실은 모든 필드 결합을 사용하여 레코드 변수를 업데이트하는 $1부작용도 있습니다 . 이 업데이트가 없으면 원본 레코드는 개행 등을 포함하여 그대로 인쇄됩니다.$0OFS

관련 정보