2009-10-09 4 views
2

참조 내 참조 this question 첫 번째 및 두 번째 파일에서 일치하는 줄 식별자를 얻은 후 첫 번째 파일의 줄을 두 번째 file.For에 대한 줄로 바꾸려면 아래 SED를 사용하고 있습니다. 그러나 Sed는 새 파일에서 해당 행을 대체합니다. 임시 파일없이 동일한 파일에서 업데이트를 수행하는 방법 (매우 큰 파일이기 때문에)Unix 쉘 스크립팅에서 SED로 동일한 파일의 행을 바꾸는 방법은 무엇입니까?

#!/bin/ksh 
while read line 
do 
var=`echo $line|cut -c 3-25` 
while read i 
do 
var1=`echo $i|cut -c 3-25` 
if [ $var == $var1 ]; 
then 
sed -i s/$line/$i/ t1 
else 

echo "not matched" 
fi 
done < t2 
done < t1 

-i 옵션을 지정하지 않아도 결과가 표시되지 않습니다. 도와주세요.

편집 : 그렇지 않으면 임시 파일이나 스크립팅 언어없이 (덜 선호하는) 다른 최적의 방법을 제안 해주십시오.

+0

입력 파일을 표시하고 최종 출력을 나타내는 경우 – ghostdog74

+1

'거대한'이란 무엇을 의미합니까? 각 파일이 파일 시스템의 45 %를 사용하고 있고 사용할 다른 파일 시스템이 없다면 임시 파일이 필요합니다. 파일이 너무 크다면 더 큰 디스크를 구입하는 것이 좋습니다. 저장 비용이 저렴합니다. –

답변

3

이와 같이 sed을 사용하면 안됩니다.

  • 단계 모든 T2의 라인
  • (T2)의 라인 중 하나가 T1에서 현재 행을 일치하는 경우를 통해 T1의 각 행에 대한

    1. : 스크립트로 지금은 그것이 말하는 무엇을 의미 다음 T1에서 모든 라인을 통해 단계와 T1의 다음 행으로 경기를
    2. 이동을 교체하고

    의미를 반복 t1에서 한 행을 읽을 때마다 전체 t2 파일을 읽습니다. 이것은 매우 비효율적입니다.

    하위 문자열에 echocut을 사용할 필요는 없습니다. 배쉬에서 ksh을 할 수있다 :

    var=${line:3:23} 
    

    참고 : 절단 범위의 시작과 끝을위한 문자 위치를 사용하여,이 쉘 구조는 위치와 문자 그래서 당신은 그에 따라 숫자를 조정해야 할 계산 시작 사용하는 반면.

    T2는 T1에서 만들어 질 교체의 목록 인 경우는, 따라서 T2는 종류의 "스크립트"입니다, 다음이 당신이 필요로 할 수 있습니다

    keystart=3 
    keylen=23 
    while read line 
    do 
        var="${line:$keystart:$keylen}" 
        if ((${#var} == keylen)) # need "$" then don't need "$" 
        then 
         sed -in "/^.\{$keystart\}$var/ c$line" t1 # use double-quote so vars get expanded 
        fi 
    done < t2 
    

    모든 라인을 찾을 수 t1에서 t2의 각 라인이 일치하고 교체를 수행합니다.

    하는 경우는, 그러나, T1과 T2는 라인에 선 대응을하고 해당 라인이 일치 어디 만 교체하려면, 다음이 임시 파일을 사용하여, 가장 효율적입니다 :

    tempfile=$(mktemp) 
    keystart=3 
    keylen=23 
    while read line1 
    do 
        var1="${line1:$keystart:$keylen}" 
        read line2 <&3 # use file descriptor 3 for input 
    
        var2="${line2:$keystart:$keylen}" 
        if [[ $var1 == $var2 && ${#var2} == $keylen ]] 
        then 
         echo "${line2}" >> $tempfile # substitute when matched 
        else 
         echo "${line1}" >> $tempfile # keep when not matched 
        fi 
    done < t1 3< t2 # t1 is input on stdin, t2 is input on fd 3 
    mv t1 t1.bak && mv $tempfile t1 
    
  • +0

    고마워요. 나는 그것을 조사하고있다. –

    2

    한 줄을 다른 줄로 바꿀 수 없습니다. 선은 일반적으로 길이가 다르므로 서로 겹칠 것이기 때문입니다. 파일의 모든 줄이 동일한 길이이면 작동 할 수 있습니다. 또한이 작업 (예 : Perl)에 더 적합한 언어를 사용하는 것이 좋습니다. Shell에서 코드가 복잡하기 때문입니다. 임시 파일이있는 솔루션을 찾아야한다고 생각합니다. 구현하기가 쉽고 쉽게 디버깅 할 수 있기 때문입니다. 대용량 파일이 스크립트의 버그로 인해 손상 될 경우 무엇을 할 것인지 상상해보십시오.

    4

    moreutils의 일부인 스펀지를 살펴보십시오.

    % sed "s/root/toor/" /etc/passwd | grep -v joey | sponge /etc/passwd 
    
    1

    Sed는 파이프 라인에서 작동하도록 설계되었으므로 "Stream EDitor"라는 이름을 사용합니다. 대신 ex 스크립트를 사용하여 파일을 편집 할 수 있습니다. Ex는 라인 기반 텍스트 편집기로 vi가 원래 기반으로되어 있습니다 (예전의 곰 스킨과 스톤 나이프 텍스트 편집기와 거의 같지 않습니다). 당신의 목적으로 수 있습니다에 대한 수정 할 수있는 간단한 예는 다음과 같습니다

    ex t1 << EOF 
    $lineNum 
    s/^.*$/$newline/ 
    w 
    q 
    EOF 
    

    이 스크립트는 처음 $ LINENUM로 표시된 라인으로 이동이 내용으로 시작하는 라인 전체 (^) 종료 ($)를 대체 $ newline을 입력 한 다음 작성하고 종료합니다. 이 명령은 기본적으로 "here"문서를 구성하는 "<<EOF"과 "EOF"으로 둘러싸여 있으며 스크립트 명령을 본질적으로 stdin으로 설정합니다.

    관련 문제