如何复制并粘贴开始关键字和结束关键字之间的行?

如何复制并粘贴开始关键字和结束关键字之间的行?

我有两个文本文件,我想将一堆行从一个复制到另一个。文件一有一个包列表,我想将其复制到列表二。此包列表不在文件一的开头,但在列表开头有一个标记 %packages,在末尾有一个标记 %end。我想知道如何将 %packages 和 %end 之间的所有行从文件 1 复制到文件 2 中?

答案1

要将 %packages 和 %end 之间的所有行从 file1 复制到 file2:

awk '$1=="%end" {f=0;next} f{print;next} $1=="%packages" {f=1}' file1 >>file2

此解决方案旨在删除 %packages 和 %end 行。 (如果您也希望转移这些线路,下面有一个更简单的解决方案。)

由于awk隐式循环文件中的所有行,因此上述命令将应用于file1.它使用一个名为 的标志f来确定我们是否在 的包部分内file1。包部分中的每一行都会打印到 stdout,然后重定向到file2.

让我们awk一一考虑这些命令:

  • $1=="%end" {f=0;next}

    此命令检查该行是否以%end.如果是,则该标志f设置为零,然后我们跳到该next行。

  • f{print;next}

    该命令检查标志是否f非零。如果它非零,则打印该行并跳到下一行。

  • $1=="%packages" {f=1}

    此命令检查该行是否以%packages.如果是,它将标志设置f为 1,以便打印此后的行。

包括标记线:

上面不包括标记行 %packages 和 %end。如果您想要包含这些内容,请使用:

awk '/^%packages/,/^%end/ {print}' file1 >>file2

答案2

除了 awk 之外,另一个需要考虑的解决方案是 sed:

sed -n '/%packages/,/%end/ w file2' file1

按出现顺序细分:
sed显然,其本身之后是一个开口'。这告诉 sed 从此时开始直到结束'是 sed 本身的参数/命令的所有内容。之后的所有内容都是输入(如果使用重定向>文件则为输出)

-n抑制打印。如果没有它,将打印 file1 的全部内容,并打印两次匹配的文本

/pattern1/,/pattern2/定义要匹配的范围的限制

w file写入文件。必须是最后一个参数,后跟文件名(如果不在当前目录中,则为 /path/to/file)

最后,关闭 single 后'我们就有了输入文件。

最后两个注意事项:

1.有些人喜欢对输入文件使用重定向,因此最终命令如下所示:

sed -n '/%packages/,/%end/ w file2' <file1

优点是更清晰 - 很明显您从哪里获得输入。同样,w file您可以重定向输出 >file ,而不是使用:

sed -n '/%packages/,/%end/ p' <file1 >file2

在这种情况下,我们添加p打印匹配项(覆盖 -n 进行选择)

但是,sed 可以对多个输入文件进行操作:

sed -n '/%packages/,/%end/ w file-final' file1 file2 file3

使用重定向往往会使用户忽视此功能。

2.上述匹配包括起始行和结束行,因为 sed 在行级别操作,而不是在字级别操作。一种解决方案可能是简单地通过管道传输到更多 sed:

sed -n '/%packages/,/%end/ w file2' file1 | sed -e '1d' -e '$d'

它引入了以下新功能:
-e允许在同一输入上运行多个命令
1显示行号匹配 工作
d是删除匹配模式 - 第一个命令中的行号 1
$是输入流的末尾。由于 sed 在行级别而不是单词级别上操作,因此末尾的整行都会被删除

但是,我们实际上可以在单个 sed 调用中执行此操作,使用大括号进行分组(为了清楚起见,在脚本中):

#!/bin/bash
sed -n '
  /%packages/,/%end/ {
    /%packages/n
    /%end/ !{
      w file2
    }
  }
' file1

这里唯一的新东西(除了分组)是使用!来否定比赛。
/pattern/n用图案抑制打印线(与-n开始时相同)。 /pattern/ !选择与模式不匹配的所有内容(反向匹配)。顺便说一句,原因很简单。如果我们采取另一个措施/%end/n来抑制 %end 模式,我们也会抑制它限制我们的范围,并且文件将被打印到末尾。

答案3

最容易理解的:

grep -A 1000 '%packages' xx | grep -B 1000 '%end'

第一部分搜索%packages并打印 1000 行(包括匹配的行)A 在它之后。

管道之后的第二部分:搜索%end并打印所有 1000 行(包括匹配的行) 之前。

如果文件超过 1000 行,请将 1000 更改为更大的数字。

如果你想仅有的匹配行,除了搜索模式之外什么都没有,包括开始和结束正则表达式,i。 e.

grep -A 1000 '^%packages$' xx | grep -B 1000 '^%end$'

如果您不想包含匹配的行,请添加另一个管道:

grep -A 1000 '^%packages$' xx | grep -B 1000 '^%end$' | grep -v -e '^%packages$' -e '^%end$'

where-e可用于指定多个搜索模式,并-v用于反转匹配的含义,以选择不匹配的行。

相关内容