파일 수정 시 첫 번째, 마지막 비어 있지 않은 줄과 빈 줄을 건너뛰는 방법은 무엇입니까?

파일 수정 시 첫 번째, 마지막 비어 있지 않은 줄과 빈 줄을 건너뛰는 방법은 무엇입니까?

다음과 같은 파일이 있습니다.

H|ACCT|XEC|1|TEMP|20130215035845

849002|48|1208004|100|||1

849007|28|1208004|100|||1

T|2|3



파일 끝에는 추가 빈 줄이 있습니다.

비어 있지 않은 첫 번째 행과 마지막 행을 제외한 모든 행에서 열 5의 값을 열 4의 값으로 바꾸고 싶습니다.

마지막 행에는 다른 행만큼 많은 필드가 있을 수 있고 항상 숫자로 시작하는 수정되는 행에 의존할 수 없기 때문에 필드 수에 의존할 수 없습니다.

다음 코드를 시도했습니다.

awk 'BEGIN{FS="|"; OFS="|"} {$5=$4; print}' in.txt

출력은 다음과 같습니다

H|ACCT|XEC|1|1|20130215035845
||||
849002|48|1208004|100|100||1
||||
849007|28|1208004|100|100||1
||||
T|2|3||
||||
||||
||||

예상 출력:

H|ACCT|XEC|1|TEMP|20130215035845|

849002|48|1208004|100|100||1

849007|28|1208004|100|100||1

T|2|3



변경을 위해 비어 있지 않은 첫 번째 행과 마지막 행을 건너뛰려면 어떻게 해야 합니까? 또한 빈 줄을 건너뛰고 싶습니다.

답변1

awk여기서는 파일을 한 번만 처리 하면 됩니다 .

awk -F'|' 'NR==1{print;next} m && NF{print m}
    NF{l="\n"$0; $5=$4; m="\n"$0; c=0}; !NF{c++}
END{ print l; for (; i++<c;)print }' OFS='|' infile

설명하다:

여기서는 스카이프를 통해 첫 번째 줄을 전송하여 필드 5 의 값을 필드 4의 값으로 바꾼 다음 인쇄하고 실행합니다 next.

...현재 다음 줄이 빈 줄이 아닌 경우(적어도 하나의 필드 포함 NF) 전체 줄을 백업하고 먼저 \newline을 추가한 다음 5번째 필드l="\n"$0 의 값 과 4번째 필드 의 값을 설정하고 마지막으로 ewline을 추가하여 변수로 설정합니다 . 다음과 같은 변수가 있습니다.$5=$4m\nm="\n"$0;c카운터!NF{c++}하나 이상의 필드가 있는 행이 표시되지 않는 경우 빈 행 수를 결정하는 데 사용되는 플래그입니다. 그렇지 않으면 c=0이 카운터가 재설정됩니다.

m이제 변수의 행을 수정했으며 m && NF{print m}다음 awk실행 에서 m설정한 위치에 인쇄 할 것이며 빈 행이 아닙니다 & NF(빈 행이 있을 때 반복 인쇄를 방지하기 위해 사용됩니다).

마지막으로 교체를 수행하기 전에 매번 백업하는 손대지 않은 마지막 줄을 인쇄한 END{ print l; ...다음 루프 필드가 있는 줄을 본 적이 없는 빈 줄의 수를 인쇄합니다 for (; i++<c;)print }'.

추가 빈 줄이 필요하지 않으면 훨씬 짧아집니다.

awk -F'|' 'NR==1{print;next} m && NF{print m}
    NF{l=$0; $5=$4; m=$0} END{ print l}' OFS='|' infile

답변2

의 경우 sed두 번째 행이 비어 있다고 가정합니다.

sed '1{n;d;};/./!{H;$g;$p;d;};x;s/|/\n/4;s/\([^|]*\)\n[^|]*/\1|\1/'

sed대체가 무엇을 의미하는지 이해하지 못하는 경우 \n대신 리터럴 개행 문자를 사용하십시오(또는 파일에 속하지 않는 것으로 알려진 문자를 사용하십시오).

설명하다:

첫 번째 줄을 제외한 줄은 예약된 공간에 수집되어 파일 끝에 도달하면 있는 그대로 인쇄되고, 그렇지 않으면 필요한 대체 항목으로 인쇄됩니다.

상세히:

  • 1{n;d;}: 첫 번째 줄은 n그대로 인쇄하고, 다음 줄을 읽고, d삭제하면 됩니다. 왜? 예약된 공간에는 인쇄할 내용이 포함되어 있으므로 어쨌든 빈 줄이 포함됩니다.
  • /./!{H;$g;$p;d;}빈 줄에서만 수행되며 H이전 공간에 추가됩니다. 마지막 줄에 대해서만 $예약된 공간을 뒤로 이동하고 인쇄합니다. 어쨌든 d해당 줄의 추가 실행을 중지하려면 삭제하세요.
  • x비어 있지 않은 라인을 보유 버퍼와 교환하여 거기에 유지하고, 비어 있지 않은 마지막 라인이 아니라는 것을 알기 때문에 이제 저장된 라인을 처리할 수 있습니다.

  • s/|/\n/4;s/\([^|]*\)\n[^|]*/\1|\1/네 번째 열을 줄바꿈 문자로 바꿔 표시하여 |열 4에서 열 5로 복사를 수행 한 다음 일치 전후의 필드를 이전 필드 크기의 두 배로 바꿉니다.

답변3

내가 말했듯이 가장 쉬운 방법은 파일을 두 번 처리하는 것입니다.
첫 번째 패스 - 줄 번호를 가져옵니다. 비어 있지 않은 마지막 줄에 대해.
두 번째 단계 - 비어 있지 않은 마지막 행 앞에 필드가 5개 이상 있는 모든 행(헤더 제외)을 처리합니다.

awk -F'|' -vc=0 'NR==FNR{if (NF){c=NR};next};
FNR>1 && NF>4 && FNR<c {$5=$4};1' OFS='|' infile infile

답변4

행에 4개의 열만 있으면 어떻게 될까요? 다섯 번째와 네 번째 열의 값을 추가해야 한다고 가정했습니다. 옳은?

첫 번째 버전 - awk 사용

awk '
BEGIN {
    FS = "|";
    OFS = "|";
} 
FNR == NR && $0 {
    last = NR;
}
FNR != NR {
    if(NF > 3 && FNR != last && FNR != 1) {
        $5 = $4;
    }
    print;
}' input.txt input.txt

동일한 코드와 주석:

awk '
BEGIN {
    FS = "|";
    OFS = "|";
} 
# The first traversing through file
# It is needed for getting the number of the last, non-empty line
FNR == NR && $0 {
    last = NR;
}
# The second traversing through file
FNR != NR {
    # if the number of fields more than 3 (therefore, the fourth column exists)
    # and the line number of the current file is not the last and not the first. 
    if(NF > 3 && FNR != last && FNR != 1) {
        $5 = $4;
    }
    print;
}' input.txt input.txt

두 번째 버전 - sed 및 tac 사용

tac input.txt | 
sed '
1,/./!{
    $!{
        s/\(|\w*\)/\1\1/3
        s/|\w*//5
    }
}' | tac 

설명하다:

  1. tac- 연결을 반대로 하고 파일을 인쇄합니다. tac그 반대이다 cat.
  2. 1,/./!- 첫 번째 행에서 비어 있지 않은 첫 번째 행(포함)까지 행을 건너뜁니다.
  3. $!- 마지막 줄을 제외한 모든 줄. 파일을 뒤집었고 마지막 줄이 실제로 첫 번째 줄이라는 것을 기억하세요.
  4. s/\(|\w*\)/\1\1/3- 네 번째 열을 복제합니다. 미용 \w보다는 사용하기로 결정했습니다 [^|]. 그러나 필드에 단어가 아닌 문자가 필요한 경우 이를 변경할 수 있습니다.
  5. s/|\w*//5- 이전의 다섯 번째 열이 제거되었습니다(현재는 여섯 번째 열).
  6. | tac- 파일을 다시 뒤집으세요.

관련 정보