sed with numeric quantifiers-방법?

Oct 02 2020

슬래시와 그 이후의 모든 것을 제거하기 위해 여러 파일의 fasta 헤더를 편집하려고합니다 ( '그 이후의 모든 항목'이 10 자 미만인 경우). 헤더 행은 '>'로 표시됩니다.

for i in ./*.fa;do sed -r 's/(>.*)\/.\{,10\}\n/\1\n/' "$i"; done

나는 또한 시도했다

for i in ./*.fa;do sed -r 's/(>.*)\/.{,10}\n/\1\n/' "$i"; done

그러나 그것은 더 나은 것 같지 않습니다. 내 직감은 일을 깨뜨리는 {, 10} 한정 자라는 것입니다. 그래도 잘 모르겠습니다. 도움을 주시면 감사하겠습니다!

예를 들어, 다음이 파일에있는 경우 :

>header1_some_extra_data_here/1-1000
ATGCGGGTACCCCA
>code/header2_some_extra_data
AGGTCCCCGGGAAAAA

다음을 출력하고 싶습니다.

>header1_some_extra_data_here
ATGCGGGTACCCCA
>code/header2_some_extra_data
AGGTCCCCGGGAAAAA

답변

7 Kusalananda Oct 02 2020 at 19:30

귀하 sed는 입력 데이터에서 개행 문자와 일치 할 수 없을 것이기 때문에 예상대로 대체 작동하지 않습니다. 그 이유는 sed줄 바꿈을 구분자로 사용하여 파일을 한 줄씩 읽고 표현식이 줄 바꿈을 구분하지 않고 줄에 개별적으로 적용되기 때문입니다.

대신 코드를 약간 변경하십시오.

for fasta in ./*.fa; do
    sed 's;^\(>.*\)/.\{0,10\}$;\1;' "$fasta"
done

내가 한 몇 가지 변경 사항은 다음과 같습니다.

  1. 기본값 대신 명령 ;의 구분 기호로 사용하십시오 . 이것은 우리가 패턴에서 탈출하지 못하게 합니다. 거의 모든 문자를 구분자로 사용할 수 있지만 패턴이나 대체 텍스트에없는 문자를 선택해야합니다.s/////
  2. 표준 기본 정규식 구문 만 사용하십시오. 패턴에서 (...)확장 정규식 구문이며 \{...\}기본 정규식 구문입니다. 이식성을 위해 기본 구문을 사용하기로 결정했습니다. 이것은 또한 -rGNU에서 확장 구문을 활성화하는 옵션을 삭제하는 것을 의미 합니다 sed.
  3. ^및 $각각을 사용 하여 패턴을 선의 시작과 끝에 고정합니다 .
  4. 대체 비트에 개행을 삽입하지 마십시오.

대안적이고 짧은 sed표현은 다음과 같습니다.

sed '/^>/s;/.\{0,10\}$;;'

이는 >문자로 시작하는 모든 행에 대체를 적용합니다 ( /^>/후속 s///명령 의 "주소"역할을 함 ). 대체는 해당 비트 길이가 10 자 이하인 경우/ 줄 끝까지 및 그 뒤에있는 비트 를 삭제합니다 .

2 terdon Oct 02 2020 at 19:48

다음은 약간 다른 방법입니다.

  1. 출력을 새 파일에 저장합니다.

    for file in *fa; do 
         sed -E 's|^\s*(>.{10,}.*)/.*|\1|' "$file" > "$file.fixed"; 
     done
    
  2. 제자리에서 파일을 편집하십시오.

    sed -i -E 's|^\s*(>.{10,}.*)/.*|\1|' *.fa 
    

이 -E옵션은 확장 정규식을 활성화합니다. 이를 통해 이스케이프 할 필요없이 ()캡처 및 {}반복에 사용할 수 있습니다. 나는 또한에 구분 기호를 변경 |명확성을 위해, 그리고 추가 ^\s*(이 힘이 지원되지 않습니다 sed, 그렇지 않은 경우, 당신이 사용할 수있는 ^ *대신) 때로는 당신이 전에 공백을 가질 수 있기 때문에 >FASTA 파일입니다.

그런 다음 트릭은 a >가 나올 때까지 뒤에 10 개 이상의 문자 를 일치 /시키고 괄호로 이러한 문자를 캡처 \1하여 일치하는 부분만으로 전체 줄을 대체하는 것입니다.

이것은 마지막 /. 따라서 /같은 줄에 여러 줄 이 있으면 마지막 줄을 제외하고 모두 유지됩니다. 예를 들면 :

$ echo ">header1_some_extra_data_here/1-1000/foo/bar/baz" | 
    sed -E 's|^\s*(>.{10,}.*)/.*|\1|' 
>header1_some_extra_data_here/1-1000/foo/bar
    

이를 방지하고 /이미 10 자 일치하는 한 첫 번째 이후의 모든 항목을 제거 하려면 다음을 사용하십시오.

sed -E 's|^\s*(>.{10}[^/]*)/.*|\1|'