쉘 스크립트에서 sed 명령을 사용하여 파일 항목을 한 줄씩 수정하는 방법은 무엇입니까?

쉘 스크립트에서 sed 명령을 사용하여 파일 항목을 한 줄씩 수정하는 방법은 무엇입니까?

이 내 꺼야 file1:

#$BQ
#{ 볼륨@홈 }
#데이터베이스바
#relationshiptcdeatid
#복사 1
#{버전 0}
#opendb
#분명한
#.루노 := 72
#.infno := 1
#.tid.noel := 101
#.tid.info := 64
#.tid.setnr := 1225              <---(1225 번호가 변경됩니다)
#.typeidm := 1
#.소스 테이블:= 2
#writedb     
#분명한
#.루노 := 72
#.infno := 205
#.tid.noel := 101
#.tid.info := 76
#.tid.setnr := 5625              <---(5625 번호가 변경됩니다)
#.typeidm := 1
#.소스 테이블:= 2
#writedb
#$EOJ

file2올바른 항목이 있습니다 .

#.tid.info := 3345              <---(이 번호를 입력하고 싶습니다.파일 164 대신)
#.tid.setnr := 1254              <---(이 번호를 입력하고 싶습니다.파일 11225 대신)
#.tid.info := 5567              <---(이 번호를 입력하고 싶습니다.파일 176 대신)
#.tid.setnr := 9056              <---(이 번호를 입력하고 싶습니다.파일 15625 대신)

file1에서 나오는 데이터를 기반으로 변경하고 싶습니다 file2.

나는 열심히 노력했다 sed "s/tid.setnr := 1225/tid.setnr := 1254/g" file1 > modified_file1

하지만 이 작업을 수동으로 수행하고 싶지는 않습니다. 스크립트에서 새 값과 값을 읽고 수정 tid.info하도록 tid.setnr하고 file2싶습니다 file1. file2에는 , 등등이 포함되어 있습니다.file1tid.infofile2file1tid.setnr

답변1

GNU sed R 명령을 사용하십시오.

sed -e 's/^#.tid.setnr :=.*//;tA;b;:A;R file2' -e 'd' file1

답변2

이를 수행하는 한 가지 방법 은 스크립트를 sed생성하는 것입니다 .sed

tmpfile=/tmp/Nainita.$$
exec 3< file2
grep -n "tid\.setnr" file1 | while IFS=: read n junk
do
        IFS= read -r line <&3  ||  break
        printf "%sc%s\n%s\n" "$n" '\' "$line"
done > "$tmpfile"
exec 3<&-
sed -f "$tmpfile" file1 > modified_file1
rm -f "$tmpfile"
  • exec 3< file2file2파일 설명자를 읽기 위해 엽니다 . 3.
  • 줄 번호별로 다음을 포함하는 줄을 찾습니다 grep -n. 이것은 루프에 공급됩니다.file1tid.setnrwhile
  • while IFS=: read n junk

    • while … read …한 번에 한 줄씩 읽는 것을 의미하며, 읽을 정보가 있는 한 반복합니다(즉, 데이터 끝에 도달하면 중지).
    • IFS=: read n junk: 첫 번째 행(즉, 원본 행 번호 ) grep -n이전의 모든 항목을 읽고 n나머지 행(이전 데이터 행) tid.setnr을 읽는다는 의미입니다 junk. 이는 신경 쓰지 않기 때문에 무시합니다.
  • IFS= read -r line <&3파일 설명자 3( )에서 한 줄을 읽고 file2, 쉘이 이를 손상시키지 않도록 지시하는 방법을 모두 수행한 다음 이름이 지정된 변수에 넣습니다 line.
  • … || break위의 작업이 read실패하면(아마도 파일 끝으로 인해) 루프를 중단하세요.
  • 썼다printfsed hange 명령은 행 번호를 가리키며 , 이는 해당 행이 변수의 내용 n으로 대체되어야 함을 나타냅니다 .line
  • done > "$tmpfile"루프의 끝을 표시 while하고 전체 루프의 표준 출력이 임을 지정합니다 $tmpfile. 결과는 다음과 같습니다.

    13c\
    #.tid.setnr := 1254
    22시\
    #.tid.setnr := 9056
    • while두 입력 중 하나에서 EOF를 얻으면 루프가 종료됩니다 . 따라서 행보다 더 많은 행이 있으면 file1추가 행은 변경되지 않은 채로 유지됩니다(즉, 해당 명령이 생성되지 않습니다). 마찬가지로, 보다 많은 행이 있는 경우 추가 행은 무시됩니다. 불행하게도 이 기능을 추가하는 것은 어렵지 않지만 이 차이점은 보고되지 않습니다.tid.setnrfile2cfile2tid.setnrfile1
  • exec 3<&-파일 설명자를 닫습니다 3.

  • sed -f "$tmpfile" file1 > modified_file1sed에서 실행 file1하고 에서 명령을 읽고 $tmpfile출력을 씁니다 modified_file1.

원하는 대로 작동해야 합니다. 물론 원하는 경우 파일 이름을 변경할 수 있습니다. "있는 그대로" 한 번 실행한 다음 파일을 살펴보고 modified_file1(또는 출력을 리디렉션하지 않도록 명령을 변경하여 sed화면에 기록) 출력이 원하는 것인지 확인해야 합니다. 그런 다음 원하는 경우 해당 위치에서 편집 sed하도록 명령을 변경할 수 있습니다 .sed -ifile1

sed명령에서 "줄 번호가 너무 많습니다"와 같은 오류가 발생 하면 $tmpfile스크립트 파일( )을 더 작은 파일로 분할해 보십시오. 각 명령은 두 줄이므로 100개 미만의 명령 크기로 시작하는 것이 좋습니다. 예를 들어 90개 명령 또는 180개 줄입니다. 텍스트 편집기1 사용하여 이 작업을 수동으로 수행할 수 있지만 이 작업을 위해 특별히 작성된 도구가 있습니다. 직관적으로 split.command 라고 합니다.

split --lines=180 "$tmpfile"

xaa스크립트는 현재 디렉터리에서 , xab, , ...라는 xac파일 로 분할됩니다 . 첫 번째N−1의 길이는 180줄입니다. 마지막 항목은 전체를 구성하는 데 필요한 모든 항목입니다(≤ 180). 예를 들어, 500개의 인스턴스가 있는 경우 tid.setnr스크립트 길이는 1000줄이 되고 6개의 x파일( xaa, xab, xac, xad) 이 xae각각 180줄로 구성되어 xaf100줄이 됩니다. 지금 그것을 할

sed -f xaa file1 > modified_file1aa

여전히 '행이 너무 많습니다'라는 메시지가 표시되면 돌아가서 행 수를 줄여 다시 시도해 보세요 --lines. 오류가 보고되지 않으면 modified_file1aa처음 90줄이 tid.setnr변경되었는지 확인하세요. 괜찮아 보이면 그렇게 하세요

sed -f xab modified_file1aa > modified_file1ab
sed -f xac modified_file1ab > modified_file1ac
sed -f xad modified_file1ac > modified_file1ad
sed -f xae modified_file1ad > modified_file1ae
sed -f xaf modified_file1ae > modified_file1af

modified_file1af이제 마지막이에요 modified_file1.

실험 하고 싶다면 다음을 수행할 수 있습니다.

  • --lines최대값이 무엇인지 찾을 때까지 더 큰 숫자를 시도해 보십시오 .
  • 노력하다

    sed -f xaa -f xab -f xac -f xad -f xae -f xaf file1 > modified_file1_test
    

    그러나 이것은 작동하지 않을 수 있습니다.

  • 위의 실험을 하시면 결과를 알려주시기 바랍니다.

이 작업을 한 번만 수행하면 완료된 것입니다. 하지만 이 작업을 반복적으로 수행해야 하는 경우 이 답변 상단에 있는 코드 블록의 마지막 두 줄을 다음으로 변경하세요.

분할 --lines=180 "$tmpfile"            <--- (물론 자신에게 맞는 숫자를 사용하세요)
cp file1 수정된 파일 1
f의 경우 x*
하다
        sed -i -f "$f" 수정된_file1
완벽한
rm -f "$tmpfile" x*

앞서 언급했듯이 이 -i옵션은 sed지정된 파일을 그 자리에서 편집하도록 지시합니다(즉, 변경 사항을 입력 파일에 다시 기록). 아니면 더 간단하게,

split --lines=180 "$tmpfile"
for f in x*
do
        sed -i -f "$f" file1
done
rm -f "$tmpfile" x*

원본을 그대로 유지할 필요가 없는 경우 file1.

사용법 요약은 다음과 같습니다 split.

나뉘다 [옵션]……[입력하다[접두사]]

기본 동작은 PREFIXaa, 등이라는 이름의 파일을 생성하는 것입니다 PREFIXab. PREFIXac즉, 기본값PREFIXx. 이름이 로 시작하는 다른 파일이 있는 경우 유일한 파일(예: 또는 )로 x정의한 다음 위의 내용을 다음으로 변경 해야 합니다.prefixprefix=Nainita.$$.prefix=/tmp/Nainita.$$.

split --lines=180 "$tmpfile" "$prefix"
for f in "$prefix"*
do
        sed -i -f "$f" file1
done
rm -f "$tmpfile" "$prefix"*

______
1 처벌을 좋아한다면,할 수 있다그렇게 하세요 sed– 그런데 왜 불장난을 합니까?

답변3

{   sed '/^#\.tid\.setnr/!d;=;g;G' |
    paste  -d'c\\\n' - - - ./addfile
}   <./mainfile | sed -f - ./mainfile

관련 줄 번호 앞에만 추가됩니다../메인 파일각 라인에. /파일 추가명령 문자열 c\<줄 바꿈>편집을 위해 결과를 sed다른 스크립트에 스크립트로 전달하기 전에./메인 파일. 샘플 데이터를 기반으로 생성된 스크립트는 다음과 같습니다.

13c\
#.tid.setnr := 1254              <--- (I want to put this number in file1 in place of 1225)
22c\
#.tid.setnr := 9056              <--- (I want to put this number in file1 in place of 5625)

... sed매달린 c선을 나타냅니다.13그리고스물 둘각 명령과 일치하는 추가 행을 출력합니다.

답변4

펄을 발견했습니다. 이 스크립트는 트릭을 수행하는 것처럼 보이는 대략적인 스크립트입니다.

#!/usr/bin/perl
#
use strict;

# subroutine to load a test file into an array
sub load{
   my $file = shift;
   open my $in, "<", $file or die "unable to open $file : $!";
   my @data = <$in>;
   chomp @data;
   foreach (@data) { s/\cM//g;}
   return @data;
}


my $file1 = shift || die "usage: $0 [file1] [file2]\n";
my @file1_data = &load($file1);
my $file2 = shift || die "usage: $0 [file1] [file2]\n";
my @file2_data = &load($file2);

my $i = 0;
foreach( @file1_data )
{
    if( $i < @file2_data ) 
    {
        my @s = split / /, $file2_data[$i];
        if( @s )
        {
            if( /^$s[0]/ )
            {
            $_ = $file2_data[$i++];
            }
        }
    }
    print "$_\n";

관련 정보