sedを使用して複数行ブロックを貪欲に削除する

sedを使用して複数行ブロックを貪欲に削除する

コードブロックが複数行であり、START-ENDブロックに空行が表示される可能性があることを考えると、usingで/** START */始まり、終了するコードブロックを貪欲に除去する方法は何ですか?/** END */sed

START は 1 行コメントを表示します。

解決策

入力する:

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 */
}

ただし、入力全体が1行にある病理学的ケースも考慮してください。

$ 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';  }  }

おすすめ記事