sed 또는 awk를 사용하여 소스 코드의 특정 부분을 주석 처리하거나 주석 처리하는 방법

sed 또는 awk를 사용하여 소스 코드의 특정 부분을 주석 처리하거나 주석 처리하는 방법

현재 내 파일에는 다음과 같은 섹션이 포함되어 있습니다.

code statement1
code statement2
# BEGIN SOMENAME
some code
some other code
# END SOMENAME
code statement n +1
code statement n +1

내가하고 싶은 것은 사이의 내용을 주석 처리하는 것입니다.

# BEGIN SOMENAME

그리고

# END

그래서 결국 다음과 같이 보입니다.

code statement1
code statement2
# BEGIN SOMENAME
# some code
# some other code
# END SOMENAME
code statement n +1
code statement n +1

awk또는 를 사용하여 이를 달성 할 수 있습니까 sed? 다시 "댓글 달기"만 하면 쉽게 되돌릴 수 있나요?

제가 피하고 싶은 것은 실수하는 것입니다. 따라서 이 줄이 이미 주석 처리되어 있으면 그대로 두어야 합니다. 또한 "주석 입력"에서 end와 start 사이의 줄이 로 시작하지 않으면 무언가를 시도해서는 안 됩니다 #.


가능한 해결책을 찾았습니다.

awk '
    BEGIN { 
        i=0; 
        line_with_no_comment_found=0 
    }
    
    /^# END/ { 
        m=0;
        if ( line_with_no_comment_found == 1 ) { 
            for (var in a) print "# "a[var] 
        } else { 
            for (var in a) print a[var] 
        }
        delete a;
        i=0;
        line_with_no_comment_found=0;
    }
    
    /^# / { 
        if (m==0) { 
            print 
        } else { 
            a[i++]=$0; 
        }
    }
    
    !/^# / { 
        if (m==0) { 
            print 
        } else { 
            a[i++]=$0; 
            line_with_no_comment_found=1
        }
    }
    
    /^# BEGIN ([a-zA-Z_])([1-9][0-9]*)*/ {
        m=1;
    }
    END { }
'<<EOF

답변1

이 스크립트는 저에게 효과적입니다. 나는 이것을 GNU Awk 4.0.1에서 테스트했지만 Nawk에서도 작동할 것입니다.

awk 'BEGIN {
    # action=0: uncomment
    # action=1: comment
    action=0
    in_optional_code_block=0
}
{
    if ($0 ~ /^# BEGIN/) {
        in_optional_code_block=1
    } else if ($0 ~ /^# END/) {
        in_optional_code_block=0
    } else if (in_optional_code_block) {
        if (action) {
            if ($0 !~ /^#/) {
                $0 = "# " $0
            }
        } else {
            if ($0 ~ /^#/) {
                sub(/^# ?/, "")
            }
        }
    }
}
1'

나는 또한 그것과 함께 제공되는 작은 쉘 스크립트를 작성했습니다:

#!/usr/bin/env sh

syntax_error() {
    echo "Usage: `basename \"$0\"` [comment|uncomment] file" >&2
    exit 1
}

case "$1" in
    0|uncomment) action=0; ;;
    1|comment) action=1; ;;
    *) syntax_error; ;;
esac
shift
if [ -z "$@" ]; then syntax_error; fi

awk 'BEGIN {
    action='$action'
    in_optional_code_block=0
}
{
    if ($0 ~ /^# BEGIN/) {
        in_optional_code_block=1
    } else if ($0 ~ /^# END/) {
        in_optional_code_block=0
    } else if (in_optional_code_block) {
        if (action) {
            if ($0 !~ /^#/) {
                $0 = "# " $0
            }
        } else {
            if ($0 ~ /^#/) {
                sub(/^# ?/, "")
            }
        }
    }
}
1' "$@" > "[email protected]"
if [ $? -eq 0 ]; then mv "[email protected]" "$@"; fi

(GNU Awk 4.1.0 이상이면 구조를 이동하는 대신 마지막에 -i 플래그를 사용할 수 있습니다.)

답변2

질문의 "가능한 솔루션"을 해결하면 제안된 코드에 몇 가지 문제가 있습니다.

  • 루프는 for (var in a)인덱스를 순서대로 반복한다고 보장되지 않으므로 a주석 처리된 행이 잠재적으로 무작위 순서로 출력될 수 있습니다.
  • BEGIN합계 행을 감지하는 데 사용하는 패턴은 END두 행에 사용된 레이블을 쌍으로 연결하려고 시도하지 않으므로 # BEGIN FOO로 끝날 수 있습니다 # END BAR.
  • /^# /블록 사이에 불필요한 코드 중복이 있습니다 !/^# /.
  • 빈 블록이 END불필요하게 존재합니다.
  • 코드의 주석 처리가 해제되지 않았습니다.

주석의 영향을 받는 섹션에서 주석 처리된 줄의 주석 처리를 쉽게 해제할 수 있도록 #열기 및 닫기 표시 줄에 추가 문자도 추가했습니다.

sed '/^# BEGIN SOMENAME$/,/^# END SOMENAME$/ s/^/#/' file

이렇게 하면 #해당 표시 줄을 포함하여 와 줄 사이의 모든 줄 시작 부분에 문자가 삽입됩니다.# BEGIN SOMENAME# END SOMENAME

특정 텍스트에 대해 다음과 같은 결과가 발생합니다.

code statement1
code statement2
## BEGIN SOMENAME
#some code
#some other code
## END SOMENAME
code statement n +1
code statement n +1

해당 문자가 아직 첫 번째 문자가 아닌 줄에만 삽입하는 경우 #표시된 줄 사이에 원래 권장되는 줄에 대한 기록이 없기 때문에 반전 작업이 매우 어렵습니다.

주석을 해제하려면:

sed '/^## BEGIN SOMENAME$/,/^## END SOMENAME$/ s/#//' file

이는 첫 번째 명령에서 권장되는 줄에만 영향을 미치며 sed각 줄의 시작 부분에 삽입된 문자를 제거하여 원래 상태로 되돌립니다.#

#공백 문자와 그 뒤에 오는 문자를 사용하여 줄을 주석 처리 하고 싶습니다 .

sed '/^# BEGIN SOMENAME$/,/^# END SOMENAME$/ s/^/# /' file

댓글을 게시하기 위해

sed '/^# # BEGIN SOMENAME$/,/^# # END SOMENAME$/ s/# //' file

댓글을 취소하는데 사용됩니다.


awk대신 동등한 작업을 사용하십시오 sed.

의견:

awk '$0 == "# BEGIN SOMENAME", $0 == "# END SOMENAME" { $0 = "#" $0 }; 1' file

댓글을 취소하려면:

awk '$0 == "## BEGIN SOMENAME", $0 == "## END SOMENAME" { $0 = substr($0, 2) }; 1' file

두 명령 모두 정규식 대신 문자열 비교를 사용합니다. 왜냐하면 정규식은 일반적으로 더 빠르고 패턴 일치가 필요하지 않기 때문입니다. 주석 해제를 위한 두 번째 명령 호출은 substr()입력 문자열에서 첫 번째 문자를 뺀 값을 반환합니다. 후행만으로 1현재 행이 출력됩니다.

관련 정보