Bash:在模式之后将一个文件的内容插入另一个文件中

时间:2013-05-29 10:13:46

标签: linux bash shell sh

我正在尝试编写一个bash脚本,它将执行以下操作:

  1. 从第一个文件中读取内容(作为第一个参数)
  2. 从第二个文件中读取内容(作为第二个参数)
  3. 使用给定模式(作为第三个参数)
  4. 查找第二个文件中的行
  5. 将第一个文件中的文本插入到模式行之后的第二个文件中。
  6. 在屏幕上打印最终文件。
  7. 例如:

    first_file.txt:

    111111
    1111
    11
    1
    

    second_file.txt:

    122221
    2222
    22
    2
    

    图案:

    2222
    

    输出:

    122221
    111111
    1111
    11
    1
    2222
    111111
    1111
    11
    1
    22
    2
    

    我应该使用什么来实现BASH上的这项功能?

    我编写了代码,但它无法正常工作(为什么?):

        #!/bin/bash
    
        first_filename="$1"
        second_filename="$2"
        pattern="$3"
    
        while read -r line
        do
        if [[ $line=˜$pattern ]]; then
                while read -r line2
                do
                        echo $line2
                done < $second_filename
        fi
        echo $line
        done < $first_filename
    

5 个答案:

答案 0 :(得分:30)

sed可以在没有循环的情况下做到这一点。使用其r命令:

sed -e '/pattern/rFILE1' FILE2

测试环节:

$ cd -- "$(mktemp -d)" 
$ printf '%s\n' 'nuts' 'bolts' > first_file.txt
$ printf '%s\n' 'foo' 'bar' 'baz' > second_file.txt
$ sed -e '/bar/r./first_file.txt' second_file.txt
foo
bar
nuts
bolts
baz

答案 1 :(得分:6)

使用 awk 也可以。

要在###标记###行之前插入:

// for each <line> of second_file.txt :
//   if <line> matches regexp ###marker###, outputs first_file.txt.
//   **without any condition :** print <line>
awk '/###marker###/ { system ( "cat first_file.txt" ) } \
     { print; } \' second_file.txt

在### marker ### line:

之后插入
// for each <line> of second_file.txt :
//   **without any condition :** print <line>
//   if <line> matches regexp ###marker###, outputs first_file.txt.
awk '{ print; } \
     /###marker###/ { system ( "cat first_file.txt" ) } \' second_file.txt

替换### marker ### line:

// for each <line> of second_file.txt :
//   if <line> matches regexp ###marker###, outputs first_file.txt.
//   **else**, print <line>
awk '/###marker###/ { system ( "cat first_file.txt" ) } \
     !/###marker###/ { print; }' second_file.txt

如果要进行就地替换,请使用临时文件以确保在awk读取整个文件之前管道未启动;添加:

> second_file.txt.new
mv second_file.txt{.new,}
// (like "mv second_file.txt.new second_file.txt", but shorter to type !)

如果您想在线内更换(仅替换模式并保留线的其余部分),则应使用 sed 来实现类似的解决方案,而不是的 AWK

答案 2 :(得分:2)

我像这样使用sed,它可以作为魅力

sed -i -e&#39; / pattern / r filetoinsert&#39; filetobeinserted

它的作用是插入&#39; filetoinsert&#39;进入&#39; filetobeinserted&#39;在具有指定模式的行

之后

注意选择一个独特的模式,不确定它如何与重复的模式一起使用,我认为它只会在第一个模式中使用

答案 3 :(得分:1)

=~运算符周围需要空格。比较:

[[ foo=~bar ]]
[[ foo =~ bar ]]

这是因为第一个表达式基本上评估为“这个字符串是空的吗?”

此外, OP代码使用small tilde而不是tilde

即便如此,你也可以轻松摆脱内循环。只需将整个while read -r line2位替换为cat -- "$second_filename"

如果文件以换行符(使用* nix工具标准)结束,则您的上一个echo $line才有效。相反,您应该使用while read -r line || [[ $line ~= '' ]]。这最终有或没有换行。

另外,Use More Quotes™

答案 4 :(得分:1)

这应该有效:

perl -lne 'BEGIN{open(A,"first_file.txt");@f=<A>;}print;if(/2222/){print @f}' second_file.txt

测试:

> cat temp
111111
1111
11
1
> cat temp2
122221
2222
22
2
> perl -lne 'BEGIN{open(A,"temp");@f=<A>;}print;if(/2222/){print @f}' temp2
122221
111111
1111
11
1

2222
111111
1111
11
1

22
2
>