用文件内容替换文件中的字符串,同时保留标签

时间:2016-08-27 08:28:26

标签: bash unix sed

我想问一下如何在保留标签的同时用文件内容替换文件中的字符串。例如:

要转换的文件:

first line
second line
        string_to_substitute
forth line
fifth line

包含内容的文件:

{
    "string1":"test",
    "string2":"test2"
}

我希望实现的结果(用文件内容替换string_to_substitute):

first line
second line
        {
            "string1":"test",
            "string2":"test2"
        }
forth line
fifth line

我尝试了sedperl替换,但只取得了类似的结果:

first line
second line
        {
    "string1":"test",
    "string2":"test2"
}
forth line
fifth line

first line
second line
{
    "string1":"test",
    "string2":"test2"
}
forth line
fifth line

4 个答案:

答案 0 :(得分:1)

这个单一的awk命令可以处理这个:

awk 'FNR==NR{
   a = a (a=="" ? "":RS) $0
   next
}
/string_to_substitute/ {
   sub(/[^[:blank:]].*$/, "")
   gsub(/\n/, "\n" $0, a)
   $0 = $0 a
} 1' content.txt file.txt

first line
second line
    {
        "string1":"test",
        "string2":"test2"
    }
forth line
fifth line

答案 1 :(得分:0)

这是一个awk解决方案:

$ awk -v f=content '/string_to_substitute/{sub(/[^\t].*/, ""); while (getline new<f) print $0 new; close(f); next} 1' file1
first line
second line
        {
                "string1":"test",
                "string2":"test2"
        }
forth line
fifth line

因为这种方法不需要将任何文件读入内存,所以即使对于大文件也应如此。

如何运作

  • -v f=content

    这会将带有新内容的文件名称分配给awk变量f

  • /string_to_substitute/{...}

    当我们到达与正则表达式string_to_substitute匹配的行时,我们执行花括号中的命令。我们将在下面讨论以下每个命令:

    • sub(/[^\t].*/, "")

      这将从当前行$0中删除从非制表符到行尾的所有内容。换句话说,这只保留当前行的缩进标签。

    • while (getline new<f) print $0 new

      循环遍历文件f并打印每行所需的缩进。

    • close(f)

      这会关闭文件f

    • next

      这告诉awk跳过剩余的命令并跳转到next行。

  • 1

    我们到达此处,我们不在string_to_substitute行。

    1是用于打印线的awk简洁速记。

命令的多行版本

对于那些发现如果命令分布在多行上更容易理解的人:

awk -v f=content '

    /string_to_substitute/{
        sub(/[^\t].*/, "")
        while (getline new<f)
           print $0 new
        close(f)
        next
    }

    1

    ' file1

答案 2 :(得分:0)

Perl救援:

#!/usr/bin/perl
use warnings;
use strict;

my ($content_filename, $to_transform_filename) = @ARGV;

my @content_lines = do {
    open my $CONTENT, '<', $content_filename or die $!;
    <$CONTENT>;
};

open my $TO_TRANSFORM, '<', $to_transform_filename or die $!;
while (<$TO_TRANSFORM>) {
    if (my ($prefix) = /^(\s*)string_to_substitute$/) {
        print "$prefix$_" for @content_lines;
    } else {
        print;
    }
}

另存为transform,以perl transform -- content-file file-to-transfer运行。

它首先读取&#34;内容&#34;的内容。将文件存入@content_lines数组。 然后,它逐行读取另一个文件,当该行包含要替换的字符串时,它会记住它之前的空白\s*并将其预先添加到数组中的每一行。打印不匹配的行没有任何变化。

答案 3 :(得分:0)

Pure bash解决方案 - 将内容文件作为参数

contentf=$1
pat="^(\s*)string_to_substitute"
while IFS= read -r line; do
  unset IFS
  if [[ ! $line =~ $pat ]]; then
    echo "$line"
    continue
  fi
  pfx=${BASH_REMATCH[1]}
# can use sed instead of inner while read loop
# sed "s/^/$pfx/" $contentf
  while IFS= read -r contentline; do
    unset IFS
    echo "$pfx$contentline"
  done <$contentf
done