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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16811173/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 05:32:19  来源:igfitidea点击:

Bash: Inserting one file's content into another file after the pattern

linuxbashshellsh

提问by user2431907

I'm trying to write a bash script, which will do the following:

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

  1. reads the content from the first file (as a first argument)
  2. reads the content from the second file (as a second argument)
  3. finds the line in the second file with the given pattern (as a third argument)
  4. inserts text from the first file to the second file after the line of the pattern.
  5. prints final file on the screen.
  1. 从第一个文件中读取内容(作为第一个参数)
  2. 从第二个文件中读取内容(作为第二个参数)
  3. 在第二个文件中找到给定模式的行(作为第三个参数)
  4. 将文本从第一个文件插入到模式行之后的第二个文件中。
  5. 在屏幕上打印最终文件。

For example:

例如:

first_file.txt:

first_file.txt:

111111
1111
11
1

second_file.txt:

第二个文件.txt:

122221
2222
22
2

pattern:

图案:

2222

output:

输出:

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

What should I use to realize this functionality on BASH?

我应该用什么来在 BASH 上实现这个功能?

I wrote the code, but it doesn't work properly (why?):

我写了代码,但它不能正常工作(为什么?):

    #!/bin/bash

    first_filename=""
    second_filename=""
    pattern=""

    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

采纳答案by l0b0

You need spaces around the =~operator. Compare:

您需要在=~运算符周围留出空间。相比:

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

This is because the first expression essentially evaluates as "Is this string empty?"

这是因为第一个表达式基本上计算为“这个字符串是否为空?”

Also, the OP code uses small tilderather than tilde.

此外,OP 代码使用小波浪号而不是波浪号

Even so, you can easily get rid of the inner loop. Just replace the whole while read -r line2bit with cat -- "$second_filename".

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

Your last echo $lineis only correct if the file does notend in a newline character (standard with *nix tools). Instead, you should use while read -r line || [[ $line ~= '' ]]. This works with or without newline at the end.

你最后echo $line是唯一正确的,如果该文件没有没有在一个换行符(与* nix的工具标准)结束。相反,您应该使用while read -r line || [[ $line ~= '' ]]. 这在最后有或没有换行符都有效。

Also, Use More Quotes?.

另外,使用更多引号?.

回答by choroba

sedcan do that without loops. Use its rcommand:

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

sed -e '/pattern/rFILE1' FILE2

Test session:

测试环节:

$ 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

回答by Pierre-Olivier Vares

Using awkworks as well.

使用awk也可以。

To insert before the ###marker### line :

在###marker### 行之前插入:

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

To insert after the ###marker###line :

在 ###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

To replace the ###marker### line :

替换 ###marker### 行:

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

If you want to do in-place replacement, use a temp file for being sure the pipe doesn't start before awk has read the entire file; add :

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

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

If you want replacement inside of the line, (replacing just the pattern and keeping the rest of the line), a similar solution should be achievable with sedinstead of awk.

如果您想在行内进行替换(仅替换模式并保留行的其余部分),则应该可以使用sed而不是awk来实现类似的解决方案。

回答by Julio Leiva

I use sed like this and it worked as a charm

我像这样使用 sed,它很有魅力

sed -i -e '/pattern/r filetoinsert' filetobeinserted

sed -i -e '/pattern/r filetoinsert' filetobeinsert

What it does is insert the 'filetoinsert' into 'filetobeinserted' after the line with the specified pattern

它的作用是在具有指定模式的行之后将 'filetoinsert' 插入到 'filetobeinsert' 中

Take care to choose a unique pattern, not sure how it will work with a duplicate patterns, I assume it will do it just of the first one

小心选择一个独特的模式,不确定它如何与重复的模式一起工作,我认为它只会做第一个

回答by Vijay

This should work:

这应该有效:

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

Tested:

测试:

> 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
>