sed를 사용하여 여러 줄 블록을 탐욕스럽지 않게 삭제

sed를 사용하여 여러 줄 블록을 탐욕스럽지 않게 삭제

코드 블록이 여러 줄이고 START-END 블록에 빈 줄이 나타날 수 있다는 점을 고려하면 /** START */using으로 시작하고 끝나는 코드 블록을 탐욕스럽지 않게 제거하는 방법은 무엇입니까?/** END */sed

START는 한 줄 주석을 표시합니다.

해결책

입력하다:

class MyClass {
    keepField;
    /** START */
    deleteField;
    /** END */

    construct() {
        /** START */
        this.deleteField = 'delete';
        /** END */
        this.keepField = 'keep';
        /** START */
        this.deleteFunc();
        /** END */
    }
    
    /** START */
    deleteFunc() {
        this.keepField = 'delete';

        if (true) {
            console.debug('Line before if statement is empty.');
        }
    } /** END */
}

산출:

class MyClass {
    keepField;

    construct() {
        this.keepField = 'keep';
    }
    
}

나는 다음 sed '/./{H;$!d} ; x ; s/START.*END//' MyClass.js과 같이 시도했습니다sed 매뉴얼>다중 라인 기술 섹션.

그러나 위의 명령은 빈 줄이 없고 여러 START-END 블록( 에서와 같이 constructor)과 빈 코드 줄이 START-END 블록 내부(함수에서와 같이)로 간주되지 않는 경우 deleteFunc블록에서 탐욕적입니다 .

sed예를 들어 다른 명령줄 도구를 사용하여 위의 문제를 해결하는 방법에 대해 알고 계시나요 awk?

START 태그는 블록 주석입니다.

해결책

입력하다:

class MyClass {
    /**
     * same code as above only this time the START block is 
     * multiline like below.
     */

    /**
     * START
     */
    deleteFunc() {
        this.keepField = 'delete';

        if (true) {
            console.debug('Line before if statement is empty.');
        }
    } /** END */
}

출력은 다음과 같아야 합니다.

class MyClass {
    keepField;

    construct() {
        this.keepField = 'keep';
    }

}

답변1

sed는 간단한 s/old/new/ 작업을 수행하기 위한 훌륭한 도구입니다. 그 외에는 명확성, 효율성, 견고성, 이식성, 유지 관리성 등을 위해 awk를 사용하세요. 예를 들어 POSIX awk를 사용하면 다음과 같습니다.

$ cat tst.awk
{ rec = rec $0 ORS }
END {
    while ( match(rec,/\/\*\*[[:space:]*]*END[[:space:]*]*\*\//) ) {
        toEnd = substr(rec,1,RSTART+RLENGTH-1)
        sub(/(\n[[:blank:]]*)?\/\*\*[[:space:]*]*START[[:space:]*]*\*\/.*/,"",toEnd)
        printf "%s", toEnd
        rec = substr(rec,RSTART+RLENGTH)
    }
    printf "%s", rec
}

$ awk -f tst.awk file
class MyClass {
    keepField;

    construct() {
        this.keepField = 'keep';
    }

}

class MyClass {
    /**
     * same code as above only this time the START block is
     * multiline like below.
     */

}

POSIX awk가 없는 경우 각각을 [:space:]to \t\n및 to로 [:blank:]변경하면 \t(각 문자열의 첫 번째 문자는 리터럴 공백 문자임) 모든 awk에서 작동합니다.

위의 코드는 이 입력 파일에서 실행됩니다.

$ cat file
class MyClass {
    keepField;
    /** START */
    deleteField;
    /** END */

    construct() {
        /** START */
        this.deleteField = 'delete';
        /** END */
        this.keepField = 'keep';
        /** START */
        this.deleteFunc();
        /** END */
    }

    /** START */
    deleteFunc() {
        this.keepField = 'delete';

        if (true) {
            console.debug('Line before if statement is empty.');
        }
    } /** END */
}

class MyClass {
    /**
     * same code as above only this time the START block is
     * multiline like below.
     */

    /**
     * START
     */
    deleteFunc() {
        this.keepField = 'delete';

        if (true) {
            console.debug('Line before if statement is empty.');
        }
    } /** END */
}

그러나 전체 입력이 한 줄에 있는 병리적인 경우도 고려하십시오.

$ cat file
class MyClass { keepField; /** START */ deleteField; /** END */ construct() { /** START */ this.deleteField = 'delete'; /** END */ this.keepField = 'keep'; /** START */ this.deleteFunc(); /** END */ } /** START */ deleteFunc() { this.keepField = 'delete'; if (true) { console.debug('Line before if statement is empty.'); } } /** END */ }

그리고 위의 스크립트는 이를 올바르게 처리합니다. (시작/끝 문자열이 리터럴 문자열 내부에 있거나 주석 내부에 있을 수 있다는 점을 제외하고는 선언되지 않은 다른 많은 경우도 처리한다고 상상할 수 있습니다. 패턴 일치를 사용하여 상황을 처리할 수는 없습니다.) 우리가 하는 것처럼요):

$ awk -f tst.awk file
class MyClass { keepField;  construct() {  this.keepField = 'keep';  }  }

답변2

GNU 사용sed

$ sed -Ez 's~ +/?\*+ START( \*)?([^*]*\*+)([^\n]*\n[^*]*\*+)? END[^\n]*\n~~g' input_file
class MyClass {
    keepField;

    construct() {
        this.keepField = 'keep';
    }
    
}
class MyClass {
    /**
     * same code as above only this time the START block is 
     * multiline like below.
     */

    /**
}

관련 정보