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

use*_*907 11 linux bash shell sh

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

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

例如:

first_file.txt:

111111
1111
11
1
Run Code Online (Sandbox Code Playgroud)

second_file.txt:

122221
2222
22
2
Run Code Online (Sandbox Code Playgroud)

图案:

2222
Run Code Online (Sandbox Code Playgroud)

输出:

122221
111111
1111
11
1
2222
111111
1111
11
1
22
2
Run Code Online (Sandbox Code Playgroud)

我应该用什么来实现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
Run Code Online (Sandbox Code Playgroud)

cho*_*oba 33

sed没有循环可以做到这一点.使用它的r命令:

sed -e '/pattern/rFILE1' FILE2
Run Code Online (Sandbox Code Playgroud)

测试环节:

$ 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
Run Code Online (Sandbox Code Playgroud)

  • +1从未听说过`r`命令.添加了测试会话以进行验证. (3认同)

Pie*_*res 7

使用awk也可以.

要在### 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
Run Code Online (Sandbox Code Playgroud)

要在### marker ###行之后插入:

// 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
Run Code Online (Sandbox Code Playgroud)

要替换### 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
Run Code Online (Sandbox Code Playgroud)

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

> second_file.txt.new
mv second_file.txt{.new,}
// (like "mv second_file.txt.new second_file.txt", but shorter to type !)
Run Code Online (Sandbox Code Playgroud)

如果你想在线内更换,(只替换模式并保留线的其余部分),应该用sed而不是awk实现类似的解决方案.


l0b*_*0b0 2

操作员周围需要有空间=~。比较:

\n\n
[[ foo=~bar ]]\n[[ foo =~ bar ]]\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n

此外,OP 代码使用小波形符而不是波形符

\n\n

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

\n\n

echo $line仅当文件不换行符结尾时(*nix 工具的标准),您的最后一个才是正确的。相反,您应该使用while read -r line || [[ $line ~= \'\' ]]. 无论末尾有或没有换行符,这都适用。

\n\n

另外,使用更多 Quotes\xe2\x84\xa2

\n