テキストファイルのパターンのコピーと置換

テキストファイルのパターンのコピーと置換

次の入力テキストファイルを考えてみましょう。

some text …
% BEGIN
blabla
foo bar
blabla
blabla
% END
some text …

そしてfoobar.txt次のファイル:

2 3
8 9 
1 2

sed(おそらく?)を使用してawkこの出力テキストファイルを取得する最も簡単な方法は何ですか?

some text …
% BEGIN
blabla
2 3
blabla
blabla
% END
% BEGIN
blabla
8 9
blabla
blabla
% END
% BEGIN
blabla
1 2
blabla
blabla
% END
some text …

答え1

これは以下を使用する純粋なawkアプローチですgetline

awk '
  /% BEGIN/ {
    s = 1;
  }

  s == 1 {
    b = b == "" ? $0 : b ORS $0
  }

  /% END/ {
    while ((getline repl < "foobar.txt") > 0) {
      tmp = b;
      sub(/foo bar/, repl, tmp);
      print tmp;
    }
    b = "";
    s = 0;
    next;
  }

  s == 0 {
    print;
  }' input

GNU awkを使用すると、一時的に交換できますgensub。以下を使用してください。

gawk '
  /% BEGIN/ {
    s = 1;
  }

  s == 1 {
    b = b == "" ? $0 : b ORS $0
  }

  /% END/ {
    while ((getline repl < "foobar.txt") > 0) {
      print gensub(/foo bar/, repl, 1, b);
    }
    b = "";
    s = 0;
    next;
  }

  s == 0 {
    print;
  }' input

テスト:

$ gawk '
>   /% BEGIN/ {s = 1;}
>   s == 1 {b = b == "" ? $0 : b ORS $0}
>   /% END/ {while ((getline repl < "foobar.txt") > 0) {print gensub(/foo bar/, repl, 1, b);} s = 0; next;}
>   s == 0 {print}' input
some text …
% BEGIN
blabla
2 3
blabla
blabla
% END
% BEGIN
blabla
8 9 
blabla
blabla
% END
% BEGIN
blabla
1 2
blabla
blabla
% END
some text …

答え2

perl -nMFatal=open -e '$l = $_;
   @ARGV and open my $fh, "<", $ARGV[0];
   print +(/^%\hBEGIN/ ? $a=0 : $a++) == 1 ? $l : $_ while <$fh>;
' foobar.txt input.txt

布材
  • foob​​ar.txtファイルから読み取った各行には、openinput.txtファイルへのファイルハンドルがありますlexical$fh語彙的でなければならない理由は、foobar.txtへの次の入力行を読むときにそれ自体が閉じられるからです。
  • $ainput.txtでこの行を見ると% BEGINカウンタを初期化します。その後、1行ではinput.txtの行をfoobar.txtの行に置き換えます。
  • パラメータの順序はfoobar.txt、input.txtです。
  • ファイルを開くとエラーを自動的に処理するプラグマFatal.pmが含まれています。
結果
some text --
% BEGIN
blabla
2 3
blabla
blabla
% END
some text --
some text --
% BEGIN
blabla
8 9
blabla
blabla
% END
some text --
some text --
% BEGIN
blabla
1 2
blabla
blabla
% END
some text --

答え3

複雑強く打つ+sed解決策:

foob​​ar_replacer.shスクリプト:

#!/bin/bash
head -n1 "$2"  # print the first line

while read -r line
do
    sed '1d;$d;{s/^foo bar$/'"$line"'/g}' "$2"        
done < "$1"

tail -n1 "$2" # print the last line

使用法:

bash foobar_replacer.sh foobar.txt input.txt

出力:

some text …
% BEGIN
blabla
2 3
blabla
blabla
% END
% BEGIN
blabla
8 9
blabla
blabla
% END
% BEGIN
blabla
1 2
blabla
blabla
% END
some text …

sedコマンドの詳細:

1d;$d;- 最初の行と最後の行を削除input.txt

s/^foo bar$/'"$line"'/gfoo bar- 次の項目を含む行を次の項目$lineに置き換えます。foobar.txt

答え4

bashスクリプトとsed使用法。使用法:、結果は新しいファイル./search_and_replace.sh < input.txtに保存されます。output.txt

#!/bin/bash

begin_str="% BEGIN"
end_str="% END"
pattern="foo bar"
write_to_var_flag=0
output_file=output.txt
foobar_file=foobar.txt
begin_to_end_block_var=""

# clean output file if it exist, else create it
> "$output_file"

function read_foobar_file () {
    while read -r line; do
        echo -ne "$begin_to_end_block_var" | sed "s/$pattern/$line/" >> "$output_file"
    done < "$foobar_file"
}

while read -r line; do
    if  [ "$line" == "$begin_str" ]; then
        write_to_var_flag=1
    fi

    if (( $write_to_var_flag )); then
        begin_to_end_block_var+="$line\n"
    else
        echo "$line" >> "$output_file"
    fi

    if [ "$line" == "$end_str" ]; then
        read_foobar_file 
        write_to_var_flag=0
    fi
done

関連情報