bash는 특정 문자를 바꾼 후 문자열의 중간 부분을 반복합니다.

bash는 특정 문자를 바꾼 후 문자열의 중간 부분을 반복합니다.

각 파일 사이에 헤더가 있는 120개의 파일(genomes.faa)이 있습니다.

>GENOME1_00001 HYPOTHETICAL PROTEIN A
NQFTIAQSQVGLEDALLDL

>GENOME1_00002 HYPOTHETICAL PROTEIN B
NQFTIAQSQVGLEDALLDL

>GENOME1_00003 HYPOTHETICAL PROTEIN C
NQFTIAQSQVGLEDALLDL

etc.

이름 뒤의 "_0000X"를 제거하고 "|"로 바꾸려고 했습니다.

>GENOME1|HYPOTHETICAL PROTEIN A
NQFTIAQSQVGLEDALLDL

>GENOME1|HYPOTHETICAL PROTEIN B
NQFTIAQSQVGLEDALLDL

>GENOME1|HYPOTHETICAL PROTEIN C
NQFTIAQSQVGLEDALLDL

etc.

나는 이것을 시도한다:

for file in *.faa
do
sed -r 's/_.*$/|/g' $file > $file.1
done

이는 나중에 "가설적인 단백질 A"를 유지하지 않으므로 다음과 같은 결과가 발생합니다.

>ERR1156171|
MMRQSVQTVLP 

바꾸다

>ERR1156171|HYPOTHETICAL PROTEIN A
MMRQSVQTVLP 

도움을 주시면 감사하겠습니다!

답변1

내 생각엔 당신이 직업 감독에 꽤 가까워진 것 같아요. 이것은 귀하가 제공한 몇 가지 예를 통해 저에게 효과적이었습니다.

sed -E 's/_[0-9]+ /|/' "$file" > "$file.1"
  • 밑줄, 숫자 및 공백 문자로만 일치를 제한하기 _.*위해 일치 표현식을 변경했습니다 ._[0-9]+
  • $첫 번째 단어의 끝이 아니라 줄의 끝과 일치하기 때문에 이를 제거했습니다 .
  • 귀하의 예제에는 여러 위치가 아닌 편집해야 하는 각 줄의 위치가 하나만 있기 /g때문에 바꾸기 명령의 끝을 에서 로 변경했습니다 ./
  • -E또한 확장 -r정규식은 다른 버전의 sed와 더 호환되므로 파일 이름에 공백이나 특수 문자가 포함된 경우 변수 확장을 인용 하지 마십시오 .

답변2

다음 Perl 한 줄 명령을 사용하세요.

perl -pe 's{^(>\S+?)(_\d+)?\s+(.*)}{$1|$3}' "$file" > "$file.1"

Perl 단일 라이너는 다음 명령줄 플래그를 사용합니다.
-e: Perl에게 파일이 아닌 인라인 코드를 찾도록 지시합니다.
-p: 한 번에 한 줄씩 입력을 반복하며 $_기본적으로 할당됩니다. print $_각 루프 반복 후에 추가됩니다.

(...): 나중에 등 $1으로 호출할 수 있는 캡처 그룹입니다 . : 공백이 아닌 하나 이상의 문자, 탐욕스럽지 않은 문자입니다. : 밑줄과 하나 이상의 숫자로 구성된 선택적 일치 그룹입니다. : 1개 이상의 공백 문자. : 0회 이상 반복되는 임의의 문자입니다.$2
\S+?
(_\d+)?
\s+
(.*)

또한보십시오:
perldoc perlrun: Perl 인터프리터 실행 방법: 명령줄 스위치
perldoc perlre:Perl 정규 표현식(정규 표현식)
perldoc perlre: Perl 정규 표현식(regexes): 수량자, 문자 클래스 및 기타 특수 이스케이프 그룹;
perldoc perlrequick: Perl 정규 표현식으로 빠른 시작

답변3

다음은 a로 시작하고 그 뒤에 하나 이상의 공백이 아닌 문자( ) _가 오는 줄에서 a가 처음 나타나는 것을 찾고 그 뒤의 모든 공백이 아닌 문자 와 모든 공백 문자를 제거하는 간단한 Perl 한 줄짜리 코드입니다.>\S_

$ perl -pe 's/^(>\S+)_\S+\s*/$1|/' file
>GENOME1|HYPOTHETICAL PROTEIN A
NQFTIAQSQVGLEDALLDL

>GENOME1|HYPOTHETICAL PROTEIN B
NQFTIAQSQVGLEDALLDL

>GENOME1|HYPOTHETICAL PROTEIN C
NQFTIAQSQVGLEDALLDL

sedGNU를 사용하여 동일한 기본 작업을 수행할 수도 있습니다.

$ sed -E 's/^(>\S+)_\S+\s*/\1|/' file
>GENOME1|HYPOTHETICAL PROTEIN A
NQFTIAQSQVGLEDALLDL

>GENOME1|HYPOTHETICAL PROTEIN B
NQFTIAQSQVGLEDALLDL

>GENOME1|HYPOTHETICAL PROTEIN C
NQFTIAQSQVGLEDALLDL

그리고 다음과 같이 sed:

$ sed 's/^\(>[^[:blank:]]*\)_[^[:blank:]]*[[:blank:]]*/\1\|/' file
>GENOME1|HYPOTHETICAL PROTEIN A
NQFTIAQSQVGLEDALLDL

>GENOME1|HYPOTHETICAL PROTEIN B
NQFTIAQSQVGLEDALLDL

>GENOME1|HYPOTHETICAL PROTEIN C
NQFTIAQSQVGLEDALLDL

답변4

특별히 bash를 요청할 때 왜 모두가 다른 언어에 대한 코드를 제공하는지 모르겠습니다.

이렇게 하려면 bash에 내장된 변수 확장 기능을 사용하세요. 이는 각 파일 이름에 대해 sed와 같은 외부 프로그램을 호출하는 것보다 훨씬 빠릅니다. 이름 수가 적은 경우에는 문제가 되지 않지만 파일 크기가 커질 수 있습니다.

암호

#!/bin/bash

for file in "GENOME1_00001 HYPOTHETICAL PROTEIN A" "GENOME1_00002 HYPOTHETICAL PROTEIN B" "GENOME1_00003 HYPOTHETICAL PROTEIN C"
  do
     echo -n $file
     new_name="${file%_*}|HYPOTHETICAL PROTEIN ${file##*EIN }"
     echo " -> ${new_name}"
  done

외부 도구를 호출하지 않고 출력을 생성합니다.

GENOME1_00001 HYPOTHETICAL PROTEIN A -> GENOME1|HYPOTHETICAL PROTEIN A
GENOME1_00002 HYPOTHETICAL PROTEIN B -> GENOME1|HYPOTHETICAL PROTEIN B
GENOME1_00003 HYPOTHETICAL PROTEIN C -> GENOME1|HYPOTHETICAL PROTEIN C

당신이 요청한대로.


주석에 설명된 대로 줄 시작 부분의 ">"는 일종의 힌트이며 이 줄만 변환되어야 한다고 가정합니다. IMHO, Sotto Voce의 반대 의견을 수용하기 위해 코드를 수정하는 것은 매우 간단하지만 다시 말하지만 그렇지 않을 수도 있습니다. Sotto Voce님의 요청에 따라 모든 대사를 처리하는 버전입니다. 여기에서는 입력 데이터를 문서로 변환했으며 이전과 마찬가지로 효율성을 위해 외부 도구가 호출되지 않았습니다.

#!/bin/bash

while read line
  do
     if [ "${line%%GENOME1_*}" = ">" ]; then
          line="${line%_*}|HYPOTHETICAL PROTEIN ${line##*EIN }"
       fi
     echo "${line}"
  done << etc
>GENOME1_00001 HYPOTHETICAL PROTEIN A
NQFTIAQSQVGLEDALLDL

>GENOME1_00002 HYPOTHETICAL PROTEIN B
NQFTIAQSQVGLEDALLDL

>GENOME1_00003 HYPOTHETICAL PROTEIN C
NQFTIAQSQVGLEDALLDL

etc

출력은 다음과 같습니다.

>GENOME1|HYPOTHETICAL PROTEIN A
NQFTIAQSQVGLEDALLDL

>GENOME1|HYPOTHETICAL PROTEIN B
NQFTIAQSQVGLEDALLDL

>GENOME1|HYPOTHETICAL PROTEIN C
NQFTIAQSQVGLEDALLDL

관련 정보