复制文本文件中的几行,并进行一些小的更改

复制文本文件中的几行,并进行一些小的更改

我正在尝试弄清楚如何复制文本文件中的单个行范围。该范围以文件中唯一的行开始,但以可存在于文件中多个位置的行结束。

这是我需要处理的一些示例输入:

我没有想象力
所以这个示例文本将
常见的
很无聊。但确实如此
展示问题
我正在努力解决。
常见的
嗨妈妈!
这是一条独特的线路。
还有更多
应复制的文本
以及。
常见的
后面应该是文字
不被复制。

我需要复制和修改的行以粗体显示,以在此处指出。

我需要的输出是:

我没有想象力
所以这个示例文本将
常见的
很无聊。但确实如此
展示问题
我正在努力解决。
常见的
嗨妈妈!
这是一条改变的线。
而这里更不一样
应复制的文本
以及。
常见的
这是一条独特的线路。
还有更多
应复制的文本
以及。
常见的
后面应该是文字
不被复制。

附加输出以粗体显示以使其清晰。

我需要获取以行开头的行范围:

这是一条独特的线路

并以以下行结尾:

常见的

该范围的行必须插入到原始范围的行之前。匹配行范围的副本需要稍微修改。

结束范围的“公共”行本身可以出现在文件内的许多位置。

我想出了一个工作awk脚本,但它似乎比需要的要复杂得多。我的awk技能根本不存在。

/This is a unique line/{flag=1}
/Common/{
    if (flag > 0) {
        n=m;
        sub("some","different",n);
        sub("unique","changed",n);
        print n "\n" $0 "\n" m;
        m=""
    };
    flag=0
};
flag{
    if (length(m) > 0) {
        m=m "\n" $0
    } else {
        m=$0
    }
}
!flag{ print }

有没有更干净、更简洁的方法来实现这个?除此之外,我对其他选择持开放态度awk。它只需是 macOS 上可用的标准命令即可。

答案1

使用ex, POSIX 指定的文件编辑器(以及 的非视觉形式vi)。

printf '%s\n' '/This is a unique line' '.,/Common/copy -' %p | ex file.txt

这会打印修改后的文件内容,但不保存更改。

这是保存更改的命令:

printf '%s\n' '/This is a unique line' '.,/Common/copy -' x | ex file.txt

与 Awk 和 Sed 不同,ex它不仅限于按顺序修改行。相反,它可以对整个缓冲区进行操作,而不仅仅是向前移动。

第一个命令/This is a unique line只是一个运动命令。它将光标移动到具有This is a unique line.

下一个命令是copy命令。它对从当前行 ( .) 到匹配的下一行的地址范围进行操作Common,并将它们复制到当前行 ( -) 之前的行。


更新:为了复制后修改,我们首先标记我们开始的行。要复制的第一行将标记为“b”,其之前的行将标记为“a”。然后复制的行将放在 'a 和 'b 之间,我们可以在地址中使用这些行作为我们的“替换”命令。顺便说一下,Andt是 的同义词。copy

printf "/Here is a unique line
kb
-ka
.,/Common/t 'a
'a+,'b-s/unique/changed/g
'a+,'b-s/some/different/g
x
" | ex file.txt

答案2

sed -e '
   /This is a unique line/,/Common/!b
   H
      /Common/!d
   g
      s/^\n//
   h
      s/unique/changed/
      s/some/different/
   G
' yourfile

解释

  • 我们首先拒绝任何非范围的行。
  • 对于范围内的每一行,我们将其附加到保留空间。
  • 我们删除所有读入的行,直到看到公共行。此时,我们检索保留区域(应该具有整个范围+前导“\n”)。
  • 我们删除这个前导换行符并更新保留。这是由于H命令 BTW 造成的。
  • 现在我们进行编辑:独特 -> 更改,一些 -> 不同,...
  • 将保留空间(未更改的版本)附加到模式空间(更改的版本)。
  • sed 将自动打印模式空间中的内容。

答案3

awk '/This is a unique line/,/Common/{
   H = H RS $0
   if ( $0 ~ /Common/ ) {
      g = H
      sub("\n","",g)
      sub("some","different",g)
      sub("unique","changed",g)
      $0 = g H
   } else { next }
}1'   inputfile

这是sed翻译为awk.

请注意,您拥有的代码负责打开/关闭awk变量标志以跟踪行。但是,当您使用它的运算符awk时,已经在幕后为您做了完全相同的事情range,

相关内容