
2개의 파일(FileA 및 FileB)이 있습니다.
파일 A:
s12 >g01
s16 >g02
s48 >g03
s52 >g04
s80 >g05
s81 >g06
s87 >g07
s91 >g08
s92 >g09
s93 >g10
s94 >g11
s96 >g12
s97 >g13
s98 >g14
s99 >g15
s100 >g16
파일 B:
s12:1148.1652412 [PCC6803]
ABCDEFGHIJKLMNOPQRST
s16:1235.1653193 [PCC6803]
UVWXYZABCDEFGHIJKLMN
s48:5877.1652308 [PCC6803]
OPQRSTUVWXYZABCDEFGH
.
.
.
FileB에 있는 모든 "FileA의 열 1 문자열"이 "FileA의 열 2 문자열"로 변경되도록 FileB를 편집하고 싶습니다.
원하는 출력:
>g01 [PCC6803]
ABCDEFGHIJKLMNOPQRST
>g02 [PCC6803]
UVWXYZABCDEFGHIJKLMN
>g03 [PCC6803]
OPQRSTUVWXYZABCDEFGH
동일한 FileB 형식으로 약 20개의 파일을 편집해야 합니다.
이런 종류의 편집을 수행하는 명령이 있습니까? 동시에 실행됩니까, 아니면 Linux 터미널에서 한 줄의 명령을 사용하여 실행됩니까? 미리 감사드립니다!
업데이트: 다음 예를 시도했습니다.여러 문자열을 매핑된 문자열의 다른 집합으로 바꾸기 하지만 작동하지 않습니다.
replacements=(
s12:\>g01
s16:\>g02
s48:\>g03
s52:\>g04
s80:\>g05
s81:\>g06
s87:\>g07
s91:\>g08
s92:\>g09
s93:\>g10
s94:\>g11
s96:\>g12
s97:\>g13
s98:\>g14
s99:\>g15
s100:\>g16
)
for row in "${replacement[@]}"; do
original="$(echo $row | cut -d: -f1)";
new="$(echo $row | cut -d: -f2)";
sed -i -e "s/${original}/${new}/g" FileB;
done
답변1
$ awk 'FNR==NR { id[$1]=$2; next } { split($1,a,":"); if (a[1] in id) $1=id[a[1]]; print }' fileA fileB
>g01 [PCC6803]
ABCDEFGHIJKLMNOPQRST
>g02 [PCC6803]
UVWXYZABCDEFGHIJKLMN
>g03 [PCC6803]
OPQRSTUVWXYZABCDEFGH
첫 번째 블록은 fileA
첫 번째 파일( )을 읽을 때만 트리거됩니다. s*
문자열을 키로 사용하여 문자열 간 매핑을 연관 배열로 읽 습니다 >g*
.id
s*
두 번째 블록은 두 번째 파일( )을 읽을 때만 트리거됩니다 fileB
. 각 행의 첫 번째 필드를 :
임시 배열로 분할합니다 a
. 분할 결과의 첫 번째 요소가 배열의 키인 경우 id
첫 번째 필드 전체가 해당 키의 값으로 대체됩니다. 그런 다음 수정되었을 수 있는 줄을 인쇄합니다.
FNR
줄 번호입니다(실제로는 레코드 번호이지만 기본적으로 레코드는 줄입니다).현재의파일이고, 은 NR
전체 줄 번호입니다. 따라서 FNR==NR
첫 번째 파일에서 읽으면.
답변2
한 가지 방법은 콘텐츠를 사용하여 sed
콘텐츠에 대한 작업 명령을 작성하는 것입니다.s///
fileA
fileB
$ sed -Ee 's/(.*) (>.*)/s|^\1:\\S+|\2|;t/' fileA | sed -Ef - fileB
산출:
>g01 [PCC6803]
ABCDEFGHIJKLMNOPQRST
>g02 [PCC6803]
UVWXYZABCDEFGHIJKLMN
>g03 [PCC6803]
OPQRSTUVWXYZABCDEFGH
설명하다:
파일 B를 변경하여 반대편에서 문제를 살펴보겠습니다. 이제 fileB의 첫 번째 줄을 편집하는 sed 명령은 어떤 모습일까요?
- 다음과 같습니다.
s/^s12:\S+/>g01/
그러면 라인 작업이 완료됩니다. 따라서 빈 줄을 표시하여t
해당 줄에 더 이상 편집이 필요하지 않음을 sed에 알립니다. - 나머지 행은 유사합니다.
- 따라서 이제 수행할 검색 n 교체의 가능한 모든 매핑을 지정하는 fileA를 살펴보는 sed 명령을 작성해야 합니다.
- 필요한 작업은 fileA를 유효한 sed s/// 명령으로 변환하여 fileB에 적용할 때 원하는 결과를 얻는 것입니다.
- 이 작업은 첫 번째 sed 명령으로 수행됩니다.
s/(.*) (>.*)/s|^\1:\\S+|\2|;t/
- 첫 번째 부분:
s/(.*) (>.*)/
sed 대체 명령의 lhs는 fileA의 특정 줄에 있는 두 필드를 가져와 저장하는 정규식입니다(예:s12 >g01
So\1
Should stores12
및\2
Should store )>g01
. 물론 여기서 언급되지 않은 가정은 이 줄에 정확히 2개의 필드가 포함되어 있으며 그 중 하나에는 공백이 있고 선행 공백이 없고 두 번째 필드는 보다 큼 부호로 시작한다는 것입니다>
. - 따라서 fileA의 행은
s12 >g01
sed 명령의 rhs에 따라 변환됩니다.s|^s12:\S+|>g01|;t
변환된 줄은 fileB에 적용되고 결과를 얻습니다. - 더 쉽게 이해할 수 있도록 파이프라인을 주석 처리하고 첫 번째 sed 명령이 생성하는 내용을 살펴보면 명확해지기 시작할 것입니다. HTH.
답변3
귀하의 sed
주문은 거의 정확합니다. 라는 배열을 정의했지만 루프 replacements
에서는 을 사용합니다 . 그것이 작동하지 않는 이유입니다. 또한 첫 번째 공백까지 전체 줄을 바꾸고 싶으므로 이것이 원하는 작업을 수행해야 합니다.for
replacement
s/$original/$new/
replacements=(
s12:\>g01
s16:\>g02
s48:\>g03
s52:\>g04
s80:\>g05
s81:\>g06
s87:\>g07
s91:\>g08
s92:\>g09
s93:\>g10
s94:\>g11
s96:\>g12
s97:\>g13
s98:\>g14
s99:\>g15
s100:\>g16
)
for row in "${replacements[@]}"; do
original="$(echo $row | cut -d: -f1)";
new="$(echo $row | cut -d: -f2)";
sed -i -e "s/^${original}:[^ ]*/${new}/g" FileB;
done
이제 교체할 때마다 전체 fileB를 처리해야 하므로 이는 매우 효율적인 접근 방식이 아닙니다. 더 빠른 방법은 다음과 같습니다.
$ awk 'NR==FNR{a[$1]=$2; next}{split($1, b, /:/); if(b[1] in a){$1=a[b[1]]}}1;' FileA FileB
>g01 [PCC6803]
ABCDEFGHIJKLMNOPQRST
>g02 [PCC6803]
UVWXYZABCDEFGHIJKLMN
>g03 [PCC6803]
OPQRSTUVWXYZABCDEFGH
그리고 여러 파일 이름을 변경하십시오.
awk 'NR==FNR{
a[$1]=$2;
next
}
{
split($1, b, /:/);
if(b[1] in a){
$1=a[b[1]]
};
print > FILENAME".fixed"
}' FileA FileB FileC FileD ... FileN
그러면 가 생성됩니다 fileB.fixed
. 까지 fileC.fixed
기다립니다 . 작동하는 것에 만족한다면 원래 파일 이름으로 다시 이름을 바꿀 수 있습니다(Ubuntu 및 Debian의 기본값인 perl-rename이 있다고 가정).fileD.fixed
FileN.fixed
rename 's/fixed//' *fixed
또는 없는 경우 perl-rename
:
for f in *fixed; do mv -- "$f" "${f%%.fixed}"; done
답변4
단 한 번의 GNU sed 호출로 이 작업을 수행할 수 있습니다. FileB 대신 FileB 형식으로 파일을 원하는 수만큼 제공할 수 있지만 FileA를 먼저 제공해야 합니다. 안전상의 이유로 이 명령은 입력 파일의 백업을 만듭니다. 수정된 파일이 만족스러우면 이후 백업 파일을 삭제해도 됩니다.
sed -ri.bk '1{x;s:^:cat /dev/fd/3:e;x};/:/{G;s/^([^:]+)\S+(\s+)([^\n]+).*\1\s+(>[^\n]+).*/\4\2\3/}' 3< FileA FileB
-i를 사용할 때 새 파일마다 예약된 공간이 삭제되는 문제를 해결하기 위해 사용자 정의 파일 설명자를 사용하는 아이디어를 제공한 @Stéphane Chazelas에게 감사드립니다.