문자열 x를 문자열 z를 기반으로 문자열 y로 대체

문자열 x를 문자열 z를 기반으로 문자열 y로 대체

(수정됨) 질문이 많은 파일이 있습니다. 예를 들어:

Chr1_RagTag_p   AUGUSTUS    transcript  393571  396143  .   +   .   transcript_id "TCONS_00000070"; gene_id "XLOC_000060"; gene_name "AT1G02100"; oId "g109.t1"; cmp_ref "AT1G02100.1"; class_code "="; tss_id "TSS64"; num_samples "1";
Chr1_RagTag_p   AUGUSTUS    exon    393571  393638  .   +   .   transcript_id "TCONS_00000070"; gene_id "XLOC_000060"; exon_number "1";
Chr1_RagTag_p   AUGUSTUS    exon    393732  393945  .   +   .   transcript_id "TCONS_00000070"; gene_id "XLOC_000060"; exon_number "2";
Chr1_RagTag_p   AUGUSTUS    exon    394047  394094  .   +   .   transcript_id "TCONS_00000070"; gene_id "XLOC_000060"; exon_number "3";
Chr1_RagTag_p   AUGUSTUS    exon    394178  394259  .   +   .   transcript_id "TCONS_00000070"; gene_id "XLOC_000060"; exon_number "4";
Chr1_RagTag_p   AUGUSTUS    exon    394457  394559  .   +   .   transcript_id "TCONS_00000070"; gene_id "XLOC_000060"; exon_number "5";
Chr1_RagTag_p   AUGUSTUS    exon    394698  394818  .   +   .   transcript_id "TCONS_00000070"; gene_id "XLOC_000060"; exon_number "6";
Chr1_RagTag_p   AUGUSTUS    exon    394911  394958  .   +   .   transcript_id "TCONS_00000070"; gene_id "XLOC_000060"; exon_number "7";
Chr1_RagTag_p   AUGUSTUS    exon    395153  395236  .   +   .   transcript_id "TCONS_00000070"; gene_id "XLOC_000060"; exon_number "8";
Chr1_RagTag_p   AUGUSTUS    exon    395347  395411  .   +   .   transcript_id "TCONS_00000070"; gene_id "XLOC_000060"; exon_number "9";
Chr1_RagTag_p   AUGUSTUS    exon    395716  395767  .   +   .   transcript_id "TCONS_00000070"; gene_id "XLOC_000060"; exon_number "10";
Chr1_RagTag_p   AUGUSTUS    exon    395957  395995  .   +   .   transcript_id "TCONS_00000070"; gene_id "XLOC_000060"; exon_number "11";
Chr1_RagTag_p   AUGUSTUS    exon    396069  396143  .   +   .   transcript_id "TCONS_00000070"; gene_id "XLOC_000060"; exon_number "12";
Chr1_RagTag_p   manual  transcript  396451  399224  .   +   .   transcript_id "TCONS_00000071"; gene_id "XLOC_000060"; gene_name "AT1G02110"; oId "g110.t1"; cmp_ref "AT1G02110.1"; class_code "="; tss_id "TSS65"; num_samples "2";
Chr1_RagTag_p   manual  exon    396451  397570  .   +   .   transcript_id "TCONS_00000071"; gene_id "XLOC_000060"; exon_number "1";
Chr1_RagTag_p   manual  exon    397661  397848  .   +   .   transcript_id "TCONS_00000071"; gene_id "XLOC_000060"; exon_number "2";
Chr1_RagTag_p   manual  exon    397923  398146  .   +   .   transcript_id "TCONS_00000071"; gene_id "XLOC_000060"; exon_number "3";
Chr1_RagTag_p   manual  exon    398367  399224  .   +   .   transcript_id "TCONS_00000071"; gene_id "XLOC_000060"; exon_number "4";
Chr1_RagTag_p   AUGUSTUS    transcript  77905   78201   .   +   .   transcript_id "TCONS_00000004"; gene_id "XLOC_000004"; oId "g15.t1"; cmp_ref "AT1G01150.1"; class_code "x"; cmp_ref_gene "AT1G01150"; tss_id "TSS4"; num_samples "1";
Chr1_RagTag_p   AUGUSTUS    exon    77905   78201   .   +   .   transcript_id "TCONS_00000004"; gene_id "XLOC_000004"; exon_number "1";

에 따르면, 예에서는 두 개의 유전자가 있음을 분명히 알 수 있지만 gene_name소프트웨어는 어떻게든 두 유전자를 하나의 유전자( gene_id)로 병합합니다. for 행을 one 으로 gene_name대체하여 gene_id이러한 문제를 해결하고 싶습니다 transcript_name. 그리고 세 번째 유전자( )에 대해서는 뒤에 부분이 없는 것으로 gene_id "XLOC_000004"이름을 바꾸고 싶습니다.oId.t[0-9]

출력은 다음과 같습니다

Chr1_RagTag_p   AUGUSTUS    transcript  393571  396143  .   +   .   transcript_id "TCONS_00000070"; gene_id "AT1G02100"; gene_name "AT1G02100"; oId "g109.t1"; cmp_ref "AT1G02100.1"; class_code "="; tss_id "TSS64"; num_samples "1";
Chr1_RagTag_p   AUGUSTUS    exon    393571  393638  .   +   .   transcript_id "TCONS_00000070"; gene_id "AT1G02100"; exon_number "1";
Chr1_RagTag_p   AUGUSTUS    exon    393732  393945  .   +   .   transcript_id "TCONS_00000070"; gene_id "AT1G02100"; exon_number "2";
Chr1_RagTag_p   AUGUSTUS    exon    394047  394094  .   +   .   transcript_id "TCONS_00000070"; gene_id "AT1G02100"; exon_number "3";
Chr1_RagTag_p   AUGUSTUS    exon    394178  394259  .   +   .   transcript_id "TCONS_00000070"; gene_id "AT1G02100"; exon_number "4";
Chr1_RagTag_p   AUGUSTUS    exon    394457  394559  .   +   .   transcript_id "TCONS_00000070"; gene_id "AT1G02100"; exon_number "5";
Chr1_RagTag_p   AUGUSTUS    exon    394698  394818  .   +   .   transcript_id "TCONS_00000070"; gene_id "AT1G02100"; exon_number "6";
Chr1_RagTag_p   AUGUSTUS    exon    394911  394958  .   +   .   transcript_id "TCONS_00000070"; gene_id "AT1G02100"; exon_number "7";
Chr1_RagTag_p   AUGUSTUS    exon    395153  395236  .   +   .   transcript_id "TCONS_00000070"; gene_id "AT1G02100"; exon_number "8";
Chr1_RagTag_p   AUGUSTUS    exon    395347  395411  .   +   .   transcript_id "TCONS_00000070"; gene_id "AT1G02100"; exon_number "9";
Chr1_RagTag_p   AUGUSTUS    exon    395716  395767  .   +   .   transcript_id "TCONS_00000070"; gene_id "AT1G02100"; exon_number "10";
Chr1_RagTag_p   AUGUSTUS    exon    395957  395995  .   +   .   transcript_id "TCONS_00000070"; gene_id "AT1G02100"; exon_number "11";
Chr1_RagTag_p   AUGUSTUS    exon    396069  396143  .   +   .   transcript_id "TCONS_00000070"; gene_id "AT1G02100"; exon_number "12";
Chr1_RagTag_p   manual  transcript  396451  399224  .   +   .   transcript_id "TCONS_00000071"; gene_id "AT1G02110"; gene_name "AT1G02110"; oId "g110.t1"; cmp_ref "AT1G02110.1"; class_code "="; tss_id "TSS65"; num_samples "2";
Chr1_RagTag_p   manual  exon    396451  397570  .   +   .   transcript_id "TCONS_00000071"; gene_id "AT1G02110"; exon_number "1";
Chr1_RagTag_p   manual  exon    397661  397848  .   +   .   transcript_id "TCONS_00000071"; gene_id "AT1G02110"; exon_number "2";
Chr1_RagTag_p   manual  exon    397923  398146  .   +   .   transcript_id "TCONS_00000071"; gene_id "AT1G02110"; exon_number "3";
Chr1_RagTag_p   manual  exon    398367  399224  .   +   .   transcript_id "TCONS_00000071"; gene_id "AT1G02110"; exon_number "4";
Chr1_RagTag_p   AUGUSTUS    transcript  77905   78201   .   +   .   transcript_id "TCONS_00000004"; gene_id "g15"; oId "g15.t1"; cmp_ref "AT1G01150.1"; class_code "x"; cmp_ref_gene "AT1G01150"; tss_id "TSS4"; num_samples "1";
Chr1_RagTag_p   AUGUSTUS    exon    77905   78201   .   +   .   transcript_id "TCONS_00000004"; gene_id "g15"; exon_number "1";


논리는 gene_nameby 를 grep transcript_id한 다음 gene_id숫자를 기준으로 각 줄의 the를 바꾸는 것 같습니다.gene_nametranscript_id

transcript_id지금까지 나는 목록 을 만들었고gene_name

TCONS_00000070 AT1G02100
TCONS_00000071 AT1G02110
TCONS_00000004 g15

gene_id그런 다음 관련 콘텐츠를 기반으로 각 행을 교체해야 합니다 . 하지만 어떻게 해야할지 모르겠습니다. 사용할 수 있나요?gene_nametranscript_idsed

마지막으로 중요한 것은 내 실제 파일이 35000개의 서로 다른 trnascript_id.

미리 감사드립니다!

답변1

이것이 모든 극단적인 경우를 다룰지는 알 수 없지만 귀하의 예에서는 귀하가 요구하는 작업을 수행합니다.

sed '/.*gene_name/{h;s///;s/;.*//;x;};G;s/gene_id[^;]*\(.*\)\n\(.*\)/gene_id\2\1/' file

gene_name콘텐츠가 있는 경우 추출하여 예약된 공간에 저장하고 새로운 콘텐츠가 나타날 gene_id때까지 모든 후속 콘텐츠의 대체 콘텐츠 로 사용합니다.gene_name

자세한 세부 사항:

  • /.*gene_name/주소, 내부의 모든 내용은 {}해당 패턴이 있는 줄에만 적용됩니다.
  • 모든 것을 엉망으로 만들기 전에 원래 행을 h이전 공간 에 저장합니다.
  • s///이전 패턴(최대 gene_name)을 삭제하고 s/;.*//세미콜론으로 시작하는 모든 항목을 삭제합니다. 따라서 남은 것은 공백과 큰따옴표로 묶인 문자열뿐입니다.
  • x두 공간을 교환하면 이제 예약된 공간에 대체 공간이 있고 패턴 공간에 원래 라인이 있습니다.
  • 이제부터 모든 내용은 모든 줄에 적용됩니다. G예약된 공백이 각 줄에 추가되므로 줄, 개행 문자 및 대체 문자가 있습니다.
  • s/gene_id[^;]*\(.*\)\n\(.*\)/gene_id\2\1/' is easier to write than to read:[^;]matches everything between유전자 ID and the( , thus the part to be replaced. The.) 대체 parts cover the text before and after the embedded newline, so we can refer to them as\1 \2`에 있습니다.and

gene_name<CR>마지막 단계를 설명하기 위해 포함된 개행 문자로 with를 사용하여 예약된 공간을 추가한 후 버퍼가 어떻게 보이는지 살펴보세요 .

Chr1_RagTag_p ………; gene_id "XLOC_000060"; exon_number "1";<CR> "AT1G02100"
                          \______v_____/\________v_______/    \____v____/
                   gene_id     [^;]*          \(.*\)       \n    \(.*\)

-E확장 정규식을 사용하면 읽기가 더 쉬울 수도 있습니다(옵션).

sed -E '/.*gene_name/{h;s///;s/;.*//;x;};G;s/(gene_id)[^;]*(.*)\n(.*)/\1\3\2/' file

gene_name업데이트는 업데이트 질문의 사례 없음을 고려합니다.

oId나는 단순히 추출물과 유사 gene_name하지만 그 전에 추출물을 추가했습니다. 따라서 그 뒤에 하나가 있으면 gene_name덮어쓰게 됩니다 oId. 이번에는 더 나은 가독성을 위해 줄을 구분합니다.

sed '
  /.*oId/{
    h
    s///
    s/\..*/"/
    x
  }
  /.*gene_name/{
    h
    s///
    s/;.*//
    x
  }
  G
  s/gene_id[^;]*\(.*\)\n\(.*\)/gene_id\2\1/' file

답변2

모든 Unix 시스템의 모든 쉘에서 awk를 사용하십시오.

$ awk '
    match($0,/gene_name "[^"]+"/) {
        name = substr($0,RSTART+10,RLENGTH-10)
    }
    match($0,/gene_id "[^"]+"/) {
        $0 = substr($0,1,RSTART+7) name substr($0,RSTART+RLENGTH)
    }
    { print }
' file
Chr1_RagTag_p   AUGUSTUS    transcript  393571  396143  .   +   .   transcript_id "TCONS_00000070"; gene_id "AT1G02100"; gene_name "AT1G02100"; oId "g109.t1"; cmp_ref "AT1G02100.1"; class_code "="; tss_id "TSS64"; num_samples "1";
Chr1_RagTag_p   AUGUSTUS    exon    393571  393638  .   +   .   transcript_id "TCONS_00000070"; gene_id "AT1G02100"; exon_number "1";
Chr1_RagTag_p   AUGUSTUS    exon    393732  393945  .   +   .   transcript_id "TCONS_00000070"; gene_id "AT1G02100"; exon_number "2";
Chr1_RagTag_p   AUGUSTUS    exon    394047  394094  .   +   .   transcript_id "TCONS_00000070"; gene_id "AT1G02100"; exon_number "3";
Chr1_RagTag_p   AUGUSTUS    exon    394178  394259  .   +   .   transcript_id "TCONS_00000070"; gene_id "AT1G02100"; exon_number "4";
Chr1_RagTag_p   AUGUSTUS    exon    394457  394559  .   +   .   transcript_id "TCONS_00000070"; gene_id "AT1G02100"; exon_number "5";
Chr1_RagTag_p   AUGUSTUS    exon    394698  394818  .   +   .   transcript_id "TCONS_00000070"; gene_id "AT1G02100"; exon_number "6";
Chr1_RagTag_p   AUGUSTUS    exon    394911  394958  .   +   .   transcript_id "TCONS_00000070"; gene_id "AT1G02100"; exon_number "7";
Chr1_RagTag_p   AUGUSTUS    exon    395153  395236  .   +   .   transcript_id "TCONS_00000070"; gene_id "AT1G02100"; exon_number "8";
Chr1_RagTag_p   AUGUSTUS    exon    395347  395411  .   +   .   transcript_id "TCONS_00000070"; gene_id "AT1G02100"; exon_number "9";
Chr1_RagTag_p   AUGUSTUS    exon    395716  395767  .   +   .   transcript_id "TCONS_00000070"; gene_id "AT1G02100"; exon_number "10";
Chr1_RagTag_p   AUGUSTUS    exon    395957  395995  .   +   .   transcript_id "TCONS_00000070"; gene_id "AT1G02100"; exon_number "11";
Chr1_RagTag_p   AUGUSTUS    exon    396069  396143  .   +   .   transcript_id "TCONS_00000070"; gene_id "AT1G02100"; exon_number "12";
Chr1_RagTag_p   manual  transcript  396451  399224  .   +   .   transcript_id "TCONS_00000071"; gene_id "AT1G02110"; gene_name "AT1G02110"; oId "g110.t1"; cmp_ref "AT1G02110.1"; class_code "="; tss_id "TSS65"; num_samples "2";
Chr1_RagTag_p   manual  exon    396451  397570  .   +   .   transcript_id "TCONS_00000071"; gene_id "AT1G02110"; exon_number "1";
Chr1_RagTag_p   manual  exon    397661  397848  .   +   .   transcript_id "TCONS_00000071"; gene_id "AT1G02110"; exon_number "2";
Chr1_RagTag_p   manual  exon    397923  398146  .   +   .   transcript_id "TCONS_00000071"; gene_id "AT1G02110"; exon_number "3";
Chr1_RagTag_p   manual  exon    398367  399224  .   +   .   transcript_id "TCONS_00000071"; gene_id "AT1G02110"; exon_number "4";

답변3

또는 다시 gawk(GNU Awk)를 사용하여 이를 수행하는 더 간단한 방법은 다음과 같습니다.

$ awk '/gene_name/ {gene_id=$14; $12=$14; print; next;} {$12=gene_id; print;}' file

또는 @EdMorton이 제안한 것처럼 더 간단합니다.

$ awk '/gene_name/ {gene_id=$14} {$12=gene_id; print}' file

Chr1_RagTag_p AUGUSTUS transcript 393571 396143 . + . transcript_id "TCONS_00000070"; gene_id "AT1G02100"; gene_name "AT1G02100"; oId "g109.t1"; cmp_ref "AT1G02100.1"; class_code "="; tss_id "TSS64"; num_samples "1";
Chr1_RagTag_p AUGUSTUS exon 393571 393638 . + . transcript_id "TCONS_00000070"; gene_id "AT1G02100"; exon_number "1";
Chr1_RagTag_p AUGUSTUS exon 393732 393945 . + . transcript_id "TCONS_00000070"; gene_id "AT1G02100"; exon_number "2";
Chr1_RagTag_p AUGUSTUS exon 394047 394094 . + . transcript_id "TCONS_00000070"; gene_id "AT1G02100"; exon_number "3";
Chr1_RagTag_p AUGUSTUS exon 394178 394259 . + . transcript_id "TCONS_00000070"; gene_id "AT1G02100"; exon_number "4";
Chr1_RagTag_p AUGUSTUS exon 394457 394559 . + . transcript_id "TCONS_00000070"; gene_id "AT1G02100"; exon_number "5";
Chr1_RagTag_p AUGUSTUS exon 394698 394818 . + . transcript_id "TCONS_00000070"; gene_id "AT1G02100"; exon_number "6";
Chr1_RagTag_p AUGUSTUS exon 394911 394958 . + . transcript_id "TCONS_00000070"; gene_id "AT1G02100"; exon_number "7";
Chr1_RagTag_p AUGUSTUS exon 395153 395236 . + . transcript_id "TCONS_00000070"; gene_id "AT1G02100"; exon_number "8";
Chr1_RagTag_p AUGUSTUS exon 395347 395411 . + . transcript_id "TCONS_00000070"; gene_id "AT1G02100"; exon_number "9";
Chr1_RagTag_p AUGUSTUS exon 395716 395767 . + . transcript_id "TCONS_00000070"; gene_id "AT1G02100"; exon_number "10";
Chr1_RagTag_p AUGUSTUS exon 395957 395995 . + . transcript_id "TCONS_00000070"; gene_id "AT1G02100"; exon_number "11";
Chr1_RagTag_p AUGUSTUS exon 396069 396143 . + . transcript_id "TCONS_00000070"; gene_id "AT1G02100"; exon_number "12";
Chr1_RagTag_p manual transcript 396451 399224 . + . transcript_id "TCONS_00000071"; gene_id "AT1G02110"; gene_name "AT1G02110"; oId "g110.t1"; cmp_ref "AT1G02110.1"; class_code "="; tss_id "TSS65"; num_samples "2";
Chr1_RagTag_p manual exon 396451 397570 . + . transcript_id "TCONS_00000071"; gene_id "AT1G02110"; exon_number "1";
Chr1_RagTag_p manual exon 397661 397848 . + . transcript_id "TCONS_00000071"; gene_id "AT1G02110"; exon_number "2";
Chr1_RagTag_p manual exon 397923 398146 . + . transcript_id "TCONS_00000071"; gene_id "AT1G02110"; exon_number "3";
Chr1_RagTag_p manual exon 398367 399224 . + . transcript_id "TCONS_00000071"; gene_id "AT1G02110"; exon_number "4";

참고:
현재 형식에서는 현재 필드에 하나 이상의 공백이 포함될 가능성이 제외되지만 이 솔루션이 더 간단해질 것이라고 생각하지 않습니다. 이를 위해서는 @EdMorton의 솔루션이 필요합니다.

답변4

저를 위해 스크립트를 작성해주신 모든 분들께 정말 감사드립니다! 어젯밤에 고민하다가 다음과 같은 방법을 생각해냈습니다.

위의 정보가 포함된 입력 파일의 이름을 Sample.gtf로 지정합니다.

나는 transcription_id, gene_id 및 gene_name을 포함하는 파일을 만들었습니다.

$ grep "oId" sample.gtf | awk '{print $10,$12,$14}' | sed 's/\"//g' | sed 's/\;//g' | sed '
s/\.[^\.]*$/ /g' > gene_id_replace_list.txt
# here I use `oId` because I found that some of the lines has no `gene_name`. In a case of no `gene_name`, I would like to grab `oId` as the a `gene_name` for replacement of `gene_id`.

$ head gene_id_replace_list.txt
TCONS_00000070 XLOC_000060 AT1G02100
TCONS_00000071 XLOC_000060 AT1G02110

sed그런 다음 위에 게시한 Phillipos와 다소 유사한 명령을 사용하여 sed에 루프를 한 줄씩 작성했습니다 .

while IFS= read -r line; do
TransId=$(echo $line | awk '{print $1}')
GeneId=$(echo $line | awk '{print $2}')
TairId=$(echo $line | awk '{print $3}')
sed -i "/${TransId}/ s/${GeneId}/${TairId}/g" sample.gtf
done < gene_id_replace_list.txt

그러나 내 전체 파일에는 35000개의 기록이 있고 지금까지 이 스크립트는 기록당 거의 1초 동안 실행되기 때문에 이 코드가 별로 마음에 들지 않습니다. 그렇다면 더 나은 제안이 있는 사람이 있나요?

위의 Philippos 명령을 적용하여 gene_name이 없는 경우를 처리하고 각 대체 항목의 transcription_id를 더 쉽게 인쇄하고 싶습니다(끝에 코드가 대체하는 것이 무엇인지 확인해야 합니다. 죄송합니다). Philippos가 제안한 것과 유사한 한 줄 명령이 sed훨씬 더 빠를 수도 있습니까?

관련 정보