텍스트 파일에서 반복되는 블록 내에서 줄을 바꾸는 방법(sed/awk 사용?)

텍스트 파일에서 반복되는 블록 내에서 줄을 바꾸는 방법(sed/awk 사용?)

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

x = {
   y = {
       z = {
           block = {
              line1
              line2
              line3
           }
        }
    }
}
x2 = {
     y2 = {
         block = {
              line4
              line5
         }
     }
}
xyz
block = {
      line6
}

등. 블록 내의 행을 뒤집어야 하지만 다른 모든 항목은 다음과 같이 순서대로 유지되어야 합니다.

x = {
   y = {
       z = {
           block = {
              line3
              line2
              line1
           }
        }
    }
}
x2 = {
     y2 = {
         block = {
              line5
              line4
              
         }
     }
}
xyz
block = {
      line6
}

sed나 awk를 사용하여 이를 수행하는 방법은 무엇입니까? 블록을 거꾸로 뒤집었지만 다시 제자리에 놓을 수는 없습니다.

sed -n '/block = {.$/,/}$/p' inputfile | tac

답변1

Perl을 사용해도 괜찮다면:

perl -ne 'if($f && /}/){$f=0; print @blk};
          $f ? unshift(@blk, $_) : print;
          if(/block = {/){$f=1; @blk=()}' ip.txt
  • if(/block = {/){$f=1; @blk=()}배열을 초기화하고 입력 행에 다음이 포함된 경우 @blk플래그를 설정합니다.$fblock = {
  • $f ? unshift(@blk, $_) : print이 플래그가 활성화되어 있으면 배열 앞에 입력 줄을 삽입하고 @blk, 그렇지 않으면 입력 줄을 인쇄합니다.
  • if($f && /}/){$f=0; print @blk}플래그가 활성화되어 있고 입력 행에 다음이 포함되어 있으면 플래그를 설정 해제하고 배열 }의 내용을 인쇄합니다.@blk

그리고 awk:

awk 'f && /}/{f=0; for(i=c; i>=1; i--) print blk[i]}
     {if(f) blk[++c] = $0; else print}
     /block = {/{f=1; c=0}' ip.txt

답변2

들여쓰기를 사용하여 해당 끝을 perl찾는 또 다른 접근 방식은 다음과 같습니다 .}block = {

perl -C -0777 -pe '
  s{^(\h*)block = \{\n\K.*?\n(?=\1\}$)}{
    join "", reverse $& =~ m{.*\n}g
  }gems' < your-file

답변3

sed코드를 작성하기는 쉽지만 읽기는 어렵다는 것을 증명해 보세요 :

sed '/block = {/,/}/{/[{}]/!{G;h;d;};x;s/.$//p;g;s/.*//;x;}' file

예약된 공간에 현재 예약된 공간을 추가하여 반전할 라인(중괄호가 없는 라인)을 모으는 것입니다(그래서 순서가 자동으로 변경됩니다). 코드는 이식 가능하며 sed어떤 구현에서도 사용할 수 있습니다. 상세히:

  • /block = {/,/}/block = {}직접 선택하는 것처럼 에서 다음까지의 각 범위를 선택하세요 . 다른 모든 유사한 코드는 xyz변경되지 않고 인쇄됩니다.
  • /[{}]/!{G;h;d;}중괄호 없이 행 처리(블록 행): G현재 예약된 공간을 추가하고 h결과를 예약된 공간으로 이동한 후 d출력과 함께 해당 행 처리를 중지합니다.
  • 나머지는 지원 라인에 대해서만 실행됩니다. 여기에서 x버퍼를 변경하여 예약된 공간에 있는 줄을 인쇄한 다음, s/.$//p예약된 빈 공간에 추가하여 도입된 예약된 공간에서 후행 줄 바꿈을 제거해야 합니다. ubstitude 명령 p에 대한 옵션은 s빈 예약 공간이 인쇄되는 것을 방지하기 위해 성공적인 대체에만 인쇄됩니다. 마지막으로 g예약된 공간에서 현재 행을 복원하는 데 사용됩니다.
  • 마지막으로 보유 공간을 비워야 합니다: s/.*//;x:현재 라인을 h이전 공간에 저장하고, 패턴 공간을 비우고 버퍼를 교체하여 보유 공간은 비워지고 패턴 공간에는 출력을 위해 현재 라인이 다시 포함됩니다.

답변4

사용행복하다(이전 Perl_6)

~$ raku -ne 'BEGIN my @blk; if (/block/ && .put) { for lines() {
             if /\}/  { put join "\n", (@blk.pop xx @blk.elems, $_); last};  
             @blk.push: $_ }
             } else { .put };'   file

#OR (more simply)

~$ raku -ne 'BEGIN my @blk; if (/block/ & .put) { for lines() { 
             if /\}/ { .put for (@blk.pop xx @blk.elems, $_).flat; last};  
             @blk.push: $_ }
             };'  file

위 코드는 Perl 계열 언어인 Raku로 작성되었습니다. -ne비자동 인쇄 플래그를 사용하여 입력을 한 줄씩 읽습니다. BEGIN블록 내에서 @blk배열이 선언되고 if"블록" 문자열(키워드)이 발견되며 lines마지막 }닫는 중괄호가 읽혀집니다. 읽어서 배열 로 lines편집 하고 Curlie 끝이 발견되면 완전히(즉, 역순으로) 닫힙니다.push@blkpop}last

입력 예:

x = {
   y = {
       z = {
           block = {
              line1
              line2
              line3
           }
        }
    }
}
x2 = {
     y2 = {
         block = {
              line4
              line5
         }
     }
}
xyz
block = {
      line6
}

예제 출력:

x = {
   y = {
       z = {
           block = {
              line3
              line2
              line1
           }
        }
    }
}
x2 = {
     y2 = {
         block = {
              line5
              line4
         }
     }
}
xyz
block = {
      line6
}

부록: @Sundeep의 뛰어난 Perl5 솔루션에 대한 Raku 번역을 찾는 사람은 다음을 참조하세요.

~$ raku -ne 'BEGIN my @blk; state $f; 
             if ($f && /\}/) {$f=0; .put for @blk}; 
             $f ?? unshift(@blk, $_) !! .put; 
             if (/block/) {$f=1; @blk=()};'  file

https://raku.org

관련 정보