1

Currently i have files, which contain sections like this

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

What i want to do is to comment out what is between "# BEGIN SOMENAME" and "# END", so that in the end it looks like this

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

Can i achieve this with awk or sed? and can i reverse it easily?, so just an operation, which "comments in" again?

What i want to avoid to make mistakes, so if the lines are already commented out it should be left alone. Also in "comment in" it should not try to do something if the lines between end and begin do not start with with a "#".

Tried that now for several hours, no success.

Found a possible solutin:

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
  • maybe, because this old code has mistakes like that multiple begin lines (copy/paste bugs...?) after another, and you just need ignore the first one or sometime the begin starts and the file ends.... i'd rather not post this script, its competly broken now.... – Mandragor Feb 2 '16 at 15:34
  • you are right. added this to challenges. Sorry got tired, and it seems always when i found a partial solution, all other things stop working – Mandragor Feb 2 '16 at 15:51
0

This script works for me. I tested it in GNU Awk 4.0.1, but should work in Nawk as well.

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'

I also wrote a small accompanying shell script:

#!/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' "$@" > ".$@.commentswap"
if [ $? -eq 0 ]; then mv ".$@.commentswap" "$@"; fi

(If you have GNU Awk 4.1.0 or later, you can use the -i flag instead of the move construction at the end.)

  • @Mandragor If SOMENAME in the opening and closing comments have to match, give me a shout. – Midgard Feb 5 '16 at 21:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.