web-dev-qa-db-ja.com

複数行にまたがっていても、括弧の間をすべて置き換えます

Bashまたはシェルスクリプトを使用して、2つの括弧の間のanythingを空白スペースに置き換えます。 2つの括弧の間のテキストは、次のように複数行になる場合があります。

myFunction (line0

line1

line2

line3

line4) 

私が変換したいもの:

myFunction ( )
6
Armin

AWK

AWKでは、条件の範囲でコードブロック_{}_を実行できます。この場合、_(_を含む行から_)_を含む行までの範囲内のすべての行でgsub()を実行します。

_$ awk '$0~/[(]/,$0~/[)]/{gsub(/line/,"newline")};1' input.txt                                                     
another line
something else

myFunction (newline0

newline1

whatever

newline2

newline3

newline4)

some other line
_

Python(元の回答)

ここに簡単なpythonスクリプトを実行します:

_#!/usr/bin/env python3
from __future__ import print_function
import sys

with open(sys.argv[1]) as fp:
    flag = None
    for line in fp:
        clean_line = line.strip()
        if "(" in clean_line: flag = True
        if flag:
           clean_line = clean_line.replace("line","newline")
        print(clean_line) 
        if ")" in clean_line: flag = False
_

テスト走行:

_$ cat input.txt                                                                                                          
another line
something else

myFunction (line0

line1

lilne2

line3

line4)

some other line
$ ./edit_function_args.py input.txt                                                                                      
another line
something else

myFunction (newline0

newline1

newline2

newline3

line4)

some other line
_

BASHバージョン

bashsedで書き換えた以外は同じスクリプト

_#!/bin/bash
flag=false
while IFS= read -r line
do

    if grep -q '('  <<< "$line"
    then
        flag=true 
    fi


    if $flag
    then
        line=$(sed 's/line/newline/'   <<< "$line") 
    fi

    printf "%s\n" "$line"


    if grep -q ')'  <<< "$line"
    then
        flag=false     
    fi

done < "$1"
_
5

@Sergのbash回答を受け取り、1行あたり2または3プロセスではなく、bashビルトインを使用するように変換します。プロセスは安価ですが無料ではありません!

#!/bin/bash
# Use Shell builtins, read, true, false, printf
flag=false
while IFS= read -r line
do
    case "$line" in
    (*"("*) flag=true ;;
    esac

    if $flag
    then
        line=${line//line/newline} 
    fi

    printf "%s\n" "$line"

    case "$line" in
    (*")"*) flag=false ;;
    esac

done < "$1"
6
icarus

Perlソリューションに問題がなく、ファイルが全体として処理できるほど小さい場合:

_$ Perl -0777 -pe 's/\([^)]+\)/$&=~s|line|newline|gr/ge' ip.txt    
myFunction (newline0

newline1

newline2

newline3

newline4) 
_
  • _-0777_入力ファイル全体を丸める
  • \([^)]+\)一致するパターン-_(_の後に_)_以外の文字が続き、_)_で終わる
  • _$&=~s|line|newline|gr_一致したパターンは、ここで_$&_を使用して参照され、必要な置換(行から改行)が行われます。 rフラグに注意して、結果を置換文字列として返します。
  • eフラグにより​​、文字列の代わりに式を使用できます
  • インプレース編集には_Perl -i -0777 -pe_を使用します
5
Sundeep

最初に提示された質問とデータについては、sed 1ライナーが機能します

  sed '/(/,/)/s/line/newline/g'

これは、(を含む行で始まり、 ')'を含む行で終わる各リージョンについて、lineをグローバルにnewlineに置き換えます。入力行の最初のgのみを変更する場合は、lineを削除します。

変更された質問については、

 sed -e '/(/{' -e ':loop;s/(.*)/()/;t;N;b loop' -e '}'

動作します。入力をループし、(が見つかるまで出力します。この時点で、区切り文字を含む()ペア内のすべてを()だけに変更しようとします。これが成功すると、ループから抜け出し、結果を出力して続行します。通常は)をまだ認識していないために、それがうまくいかなかった場合は、次の入力行を追加してループを続行します。 1行にしたくない場合は、次のように記述します。

sed -e '/(/{
:loop
s/(.*)/()/
t
N
b loop
}'

フォローしやすくなります。

4
icarus

ネストされた括弧も正しく処理したい場合は、 sgrep のように、通常の言語ではなく、文脈自由言語用のツールを使用します。

sgrep -o '%r ' '(start .. end) extracting ("("__")")' < input_file

このように、たとえば、次の

myFunction (line0

line1

(line2)

line3

line4) 

anotherFun (x y)

なる

myFunction ( ) 

anotherFun ( )
2
dirkt

明確化、コメント、改訂されたデータをすべて組み合わせると、私の申し出は次のようになります。

まず最初に、アドバイスされたmyFunction (...)ともう1つの関数を含むソースファイル_d.txt_をより現実的にすることを検討してみましょう。
ハードサイドになるために、このd.txtファイル内の2つの関数の内容が次のようにほぼ同じであると仮定します。

_$ cat d.txt
myOtherFunction (x as boolean
y as integer
d as string
e as whatever)

myFunction (xx as boolean
yy as integer
dd as string
ee as whatever)
_

別のファイル_d2.txt_に別の関数があるとしましょう。

_$ cat d2.txt
BrandNewFunction (xxx as integer
yyy as boolean
ddd as integer
eee as whatever)
_

Line、newlineなどのサンプル名を忘れて、コメントを検討すると、最初のソースコードファイル_d.txt_既存のmyFunction (..)BrandNewFunction (...)ファイル_d2.txt_に存在します。

これは、純粋なbashを使用して簡単に行うことができます。

_$ a="$(sed -n '/myFunction (/,/)/p' d.txt)" #isolates myFunction from the source file d.txt
$ b="$(cat d2.txt)" #get contents of file d2.txt (BrandNewFunction)
$ c="$(cat d.txt)" #get the whole source file d.txt
$ echo "${c/$a/$b}" #in source file d.txt ($c) replace $a with $b (d2.txt)
#Output:
myOtherFunction (x as boolean
y as integer
d as string
e as whatever)

BrandNewFunction (xxx as integer
yyy as boolean
ddd as integer
eee as whatever)
_

またはワンライナーとしても:

_$ a="$(sed -n '/myFunction (/,/)/p' d.txt)";b="$(cat d2.txt)";c="$(cat d.txt)";echo "${c/$a/$b}"
_

上記のコマンドは、置換結果(エコー)を画面に出力するだけです。結果を保存するには、エコーを_>d.txt_に送信して、既存のファイルまたは必要に応じて新しいファイルを上書きします。

Sedは行の操作に焦点を当てているため、改行で区切られた複数の行を置き換えるのはあまり良くないようです。

AWKは仕事に適していますが、AWKは得意ではありません。

Bashは、マルチラインを正常に置き換えることができる最も簡単なソリューションです。

PS1:ファイル_d2.txt_にさらに関数が含まれていて、ソースファイル_d.txt_と同様にBrandNewFunction (..)を分離する場合は、$ b変数定義を次のように変更するだけです。

_$ b="$(sed -n '/BrandNewFunction (/,/)/p' d2.txt)"
_

PS2:ソースファイルd.txtのmyFunction(...)を同じ名前の空白の関数に置き換えるだけの場合は、変数bを次のようにハードコードできます(ソースファイルd.txtのどの関数を使用するかはすでにわかっています)削除しますか?)

_$ b="myFunction ( )" 
_
2
George Vasiliou

GNUの新しいバージョンsedは-zオプションをサポートしています。

通常、sedは、行末文字(改行または改行)までの文字列を読み取ることによって行を読み取ります。
GNU sedのバージョンは、バージョン4.2.2で「NULL」文字を使用する機能を追加しました。これは、NULLを使用するファイルがある場合に役立ちます。一部のGNUユーティリティは、「find。-print0」や「grep -lZ」など、新しい行の代わりにNULLを使用する出力を生成できます。

このオプションは、sedを別の行で動作させたい場合に使用できます。

sed -z 's/([^)]*)/( )/g' inputfile
0
Walter A