复制并替换文本文件中的模式

复制并替换文本文件中的模式

让我们考虑这样一个输入文本文件:

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

在职的
  • 对于从 foobar.txt 文件中读取的每一行,我们都有open一个文件 input.txt 的文件lexical句柄。$fh它必须是词法的原因是,当读入 foobar.txt 的下一行输入时,它会自行关闭。
  • $a当我们% BEGIN在 input.txt 中看到该行时,我们会初始化计数器。在此之后的 1 行,我们将 input.txt 中的行替换为 foobar.txt 中的行。
  • 参数的顺序是:foobar.txt,然后是 input.txt。
  • 我们包含 pragma 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- 将包含下一项的行替换$linefoobar.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

相关内容