根据多个匹配项将行添加到文本文件
Add line to text file based on multiple matches
我正在尝试使用 sed、awk 或其他 Linux 标准命令修改文件,以便在匹配以某些公共字符开头的两行时,插入一行显示该部分的文本已结束。
给出的内容如下:
a 2021-08-12 14:42:21.0
b 2021-08-12 14:42:22.0
a 2021-08-12 14:42:22.0
b 2021-08-12 14:42:22.0
b 2021-08-12 14:42:23.0
c 2021-08-12 14:42:54.0
c 2021-08-12 14:42:54.0
a 2021-08-12 14:43:27.0
b 2021-08-12 14:43:27.0
a 2021-08-12 14:43:28.0
b 2021-08-12 14:43:28.0
b 2021-08-12 14:43:28.0
c 2021-08-12 14:43:59.0
c 2021-08-12 14:44:00.0
a 2021-08-12 14:44:33.0
b 2021-08-12 14:44:33.0
c 2021-08-12 14:45:06.0
a 2021-08-12 14:45:39.0
b 2021-08-12 14:45:39.0
a 2021-08-12 14:45:40.0
b 2021-08-12 14:45:40.0
b 2021-08-12 14:45:40.0
c 2021-08-12 14:46:11.0
c 2021-08-12 14:46:11.0
我想结束:
a 2021-08-12 14:45:39.0
b 2021-08-12 14:45:39.0
a 2021-08-12 14:45:40.0
b 2021-08-12 14:45:40.0
b 2021-08-12 14:45:40.0
c 2021-08-12 14:46:11.0
c 2021-08-12 14:46:11.0
##Some Text##
a 2021-08-12 14:45:39.0
b 2021-08-12 14:45:39.0
a 2021-08-12 14:45:40.0
b 2021-08-12 14:45:40.0
b 2021-08-12 14:45:40.0
c 2021-08-12 14:46:11.0
c 2021-08-12 14:46:11.0
##Some Text##
a 2021-08-12 14:44:33.0
b 2021-08-12 14:44:33.0
c 2021-08-12 14:45:06.0*
a 2021-08-12 14:45:39.0
b 2021-08-12 14:45:39.0
a 2021-08-12 14:45:40.0
b 2021-08-12 14:45:40.0
b 2021-08-12 14:45:40.0
c 2021-08-12 14:46:11.0
c 2021-08-12 14:46:11.0
##Some Text##
你可能会看到,在最后一个序列之前,有一个失败的测试没有成功完成......如果这个也能处理,那就太好了,一个结束在新数据集以 'a' 开始之前,数据集将始终为 'c',如果不容易,请不要担心,这并不经常需要担心。在这种情况下,程序每次迭代输出 7 行,但可以有任意数量的步骤。
我试过类似的东西:
sed '/3 /{p;s/.*/1/;H;g;/^\(\n1\)\{2\}$/s//##TEXT##/p;d}'
sed -z 's/^3/&\n##TEXT##/2'
sed -e '/^\[3 \]$/,/^\[2 \]/{/^1 .*/a'"##TEXT##" -e '}'
我似乎无法让它工作....找到 2 行以相同模式或字符开头的位置,在匹配后插入一些文本。
感谢任何帮助!!
谢谢
/G
这就是您要求的(在以 c
开头的 2 行背对背打印文本后):
$ awk '{print} (=="c") && (p==){ print "##Some Text##" } {p=}' file
a 2021-08-12 14:42:21.0
b 2021-08-12 14:42:22.0
a 2021-08-12 14:42:22.0
b 2021-08-12 14:42:22.0
b 2021-08-12 14:42:23.0
c 2021-08-12 14:42:54.0
c 2021-08-12 14:42:54.0
##Some Text##
a 2021-08-12 14:43:27.0
b 2021-08-12 14:43:27.0
a 2021-08-12 14:43:28.0
b 2021-08-12 14:43:28.0
b 2021-08-12 14:43:28.0
c 2021-08-12 14:43:59.0
c 2021-08-12 14:44:00.0
##Some Text##
a 2021-08-12 14:44:33.0
b 2021-08-12 14:44:33.0
c 2021-08-12 14:45:06.0
a 2021-08-12 14:45:39.0
b 2021-08-12 14:45:39.0
a 2021-08-12 14:45:40.0
b 2021-08-12 14:45:40.0
b 2021-08-12 14:45:40.0
c 2021-08-12 14:46:11.0
c 2021-08-12 14:46:11.0
##Some Text##
但我认为这可能是您实际需要的(在不以 c
开头的行之前打印文本,而在它之前的行确实以 c
开头),假设输入 c 2021-08-12 14:45:06.0*
中的行是您在“有一个失败的测试尚未成功完成……如果这也可以处理”中提到的情况,以及您想要的方式handled 是打印与我们打印该文本的其他情况相同的文本:
$ awk 'BEGIN{txt="##Some Text##"} (!=p) && (p=="c"){ print txt } {print; p=} END{ print txt }' file
a 2021-08-12 14:42:21.0
b 2021-08-12 14:42:22.0
a 2021-08-12 14:42:22.0
b 2021-08-12 14:42:22.0
b 2021-08-12 14:42:23.0
c 2021-08-12 14:42:54.0
c 2021-08-12 14:42:54.0
##Some Text##
a 2021-08-12 14:43:27.0
b 2021-08-12 14:43:27.0
a 2021-08-12 14:43:28.0
b 2021-08-12 14:43:28.0
b 2021-08-12 14:43:28.0
c 2021-08-12 14:43:59.0
c 2021-08-12 14:44:00.0
##Some Text##
a 2021-08-12 14:44:33.0
b 2021-08-12 14:44:33.0
c 2021-08-12 14:45:06.0
##Some Text##
a 2021-08-12 14:45:39.0
b 2021-08-12 14:45:39.0
a 2021-08-12 14:45:40.0
b 2021-08-12 14:45:40.0
b 2021-08-12 14:45:40.0
c 2021-08-12 14:46:11.0
c 2021-08-12 14:46:11.0
##Some Text##
或者如果您想要在以单个 c
而不是 2 c
结束的块的情况下打印不同的文本:
$ awk '
(!=p) && (p=="c"){ prt() } {print; pp=p; p=} END{ prt() }
function prt() { print (pp==p ? "##Some Text##" : "##Some Other Text##") }
' file
a 2021-08-12 14:42:21.0
b 2021-08-12 14:42:22.0
a 2021-08-12 14:42:22.0
b 2021-08-12 14:42:22.0
b 2021-08-12 14:42:23.0
c 2021-08-12 14:42:54.0
c 2021-08-12 14:42:54.0
##Some Text##
a 2021-08-12 14:43:27.0
b 2021-08-12 14:43:27.0
a 2021-08-12 14:43:28.0
b 2021-08-12 14:43:28.0
b 2021-08-12 14:43:28.0
c 2021-08-12 14:43:59.0
c 2021-08-12 14:44:00.0
##Some Text##
a 2021-08-12 14:44:33.0
b 2021-08-12 14:44:33.0
c 2021-08-12 14:45:06.0
##Some Other Text##
a 2021-08-12 14:45:39.0
b 2021-08-12 14:45:39.0
a 2021-08-12 14:45:40.0
b 2021-08-12 14:45:40.0
b 2021-08-12 14:45:40.0
c 2021-08-12 14:46:11.0
c 2021-08-12 14:46:11.0
##Some Text##
上面的 p
只是一个变量,它保存了 $1 的前一个值,而 pp
保存了 2 行后面的 $1 的值。
以下测试使用 GNU sed
4.8 和 BSD sed
版本 (2005) 由 Apple 在 macOS 上发布。
正如您从 sed
开始的那样,这里有一个 sed
解决方案。我假设您想在以 c
开头的连续两行之后插入您的文本(不确定我是否完全理解您的规格):
sed -E '/^c/{x;/^c/a\
##Some Text##
;x;};h' data.txt
最后的 h
复制保留 space 中的每一行。当一行以 c
开头(匹配 /^c/
)时,我们交换模式 space 和保留 space,如果后者也以 c
开头,我们附加文本;当然我们交换回模式 space 和保持 space.
如果您更喜欢单行命令并且您的 shell 是 bash
:
sed -E $'/^c/{x;/^c/a\\n##Some Text##\n;x;};h' data.txt
我正在尝试使用 sed、awk 或其他 Linux 标准命令修改文件,以便在匹配以某些公共字符开头的两行时,插入一行显示该部分的文本已结束。
给出的内容如下:
a 2021-08-12 14:42:21.0
b 2021-08-12 14:42:22.0
a 2021-08-12 14:42:22.0
b 2021-08-12 14:42:22.0
b 2021-08-12 14:42:23.0
c 2021-08-12 14:42:54.0
c 2021-08-12 14:42:54.0
a 2021-08-12 14:43:27.0
b 2021-08-12 14:43:27.0
a 2021-08-12 14:43:28.0
b 2021-08-12 14:43:28.0
b 2021-08-12 14:43:28.0
c 2021-08-12 14:43:59.0
c 2021-08-12 14:44:00.0
a 2021-08-12 14:44:33.0
b 2021-08-12 14:44:33.0
c 2021-08-12 14:45:06.0
a 2021-08-12 14:45:39.0
b 2021-08-12 14:45:39.0
a 2021-08-12 14:45:40.0
b 2021-08-12 14:45:40.0
b 2021-08-12 14:45:40.0
c 2021-08-12 14:46:11.0
c 2021-08-12 14:46:11.0
我想结束:
a 2021-08-12 14:45:39.0
b 2021-08-12 14:45:39.0
a 2021-08-12 14:45:40.0
b 2021-08-12 14:45:40.0
b 2021-08-12 14:45:40.0
c 2021-08-12 14:46:11.0
c 2021-08-12 14:46:11.0
##Some Text##
a 2021-08-12 14:45:39.0
b 2021-08-12 14:45:39.0
a 2021-08-12 14:45:40.0
b 2021-08-12 14:45:40.0
b 2021-08-12 14:45:40.0
c 2021-08-12 14:46:11.0
c 2021-08-12 14:46:11.0
##Some Text##
a 2021-08-12 14:44:33.0
b 2021-08-12 14:44:33.0
c 2021-08-12 14:45:06.0*
a 2021-08-12 14:45:39.0
b 2021-08-12 14:45:39.0
a 2021-08-12 14:45:40.0
b 2021-08-12 14:45:40.0
b 2021-08-12 14:45:40.0
c 2021-08-12 14:46:11.0
c 2021-08-12 14:46:11.0
##Some Text##
你可能会看到,在最后一个序列之前,有一个失败的测试没有成功完成......如果这个也能处理,那就太好了,一个结束在新数据集以 'a' 开始之前,数据集将始终为 'c',如果不容易,请不要担心,这并不经常需要担心。在这种情况下,程序每次迭代输出 7 行,但可以有任意数量的步骤。
我试过类似的东西:
sed '/3 /{p;s/.*/1/;H;g;/^\(\n1\)\{2\}$/s//##TEXT##/p;d}'
sed -z 's/^3/&\n##TEXT##/2'
sed -e '/^\[3 \]$/,/^\[2 \]/{/^1 .*/a'"##TEXT##" -e '}'
我似乎无法让它工作....找到 2 行以相同模式或字符开头的位置,在匹配后插入一些文本。
感谢任何帮助!!
谢谢 /G
这就是您要求的(在以 c
开头的 2 行背对背打印文本后):
$ awk '{print} (=="c") && (p==){ print "##Some Text##" } {p=}' file
a 2021-08-12 14:42:21.0
b 2021-08-12 14:42:22.0
a 2021-08-12 14:42:22.0
b 2021-08-12 14:42:22.0
b 2021-08-12 14:42:23.0
c 2021-08-12 14:42:54.0
c 2021-08-12 14:42:54.0
##Some Text##
a 2021-08-12 14:43:27.0
b 2021-08-12 14:43:27.0
a 2021-08-12 14:43:28.0
b 2021-08-12 14:43:28.0
b 2021-08-12 14:43:28.0
c 2021-08-12 14:43:59.0
c 2021-08-12 14:44:00.0
##Some Text##
a 2021-08-12 14:44:33.0
b 2021-08-12 14:44:33.0
c 2021-08-12 14:45:06.0
a 2021-08-12 14:45:39.0
b 2021-08-12 14:45:39.0
a 2021-08-12 14:45:40.0
b 2021-08-12 14:45:40.0
b 2021-08-12 14:45:40.0
c 2021-08-12 14:46:11.0
c 2021-08-12 14:46:11.0
##Some Text##
但我认为这可能是您实际需要的(在不以 c
开头的行之前打印文本,而在它之前的行确实以 c
开头),假设输入 c 2021-08-12 14:45:06.0*
中的行是您在“有一个失败的测试尚未成功完成……如果这也可以处理”中提到的情况,以及您想要的方式handled 是打印与我们打印该文本的其他情况相同的文本:
$ awk 'BEGIN{txt="##Some Text##"} (!=p) && (p=="c"){ print txt } {print; p=} END{ print txt }' file
a 2021-08-12 14:42:21.0
b 2021-08-12 14:42:22.0
a 2021-08-12 14:42:22.0
b 2021-08-12 14:42:22.0
b 2021-08-12 14:42:23.0
c 2021-08-12 14:42:54.0
c 2021-08-12 14:42:54.0
##Some Text##
a 2021-08-12 14:43:27.0
b 2021-08-12 14:43:27.0
a 2021-08-12 14:43:28.0
b 2021-08-12 14:43:28.0
b 2021-08-12 14:43:28.0
c 2021-08-12 14:43:59.0
c 2021-08-12 14:44:00.0
##Some Text##
a 2021-08-12 14:44:33.0
b 2021-08-12 14:44:33.0
c 2021-08-12 14:45:06.0
##Some Text##
a 2021-08-12 14:45:39.0
b 2021-08-12 14:45:39.0
a 2021-08-12 14:45:40.0
b 2021-08-12 14:45:40.0
b 2021-08-12 14:45:40.0
c 2021-08-12 14:46:11.0
c 2021-08-12 14:46:11.0
##Some Text##
或者如果您想要在以单个 c
而不是 2 c
结束的块的情况下打印不同的文本:
$ awk '
(!=p) && (p=="c"){ prt() } {print; pp=p; p=} END{ prt() }
function prt() { print (pp==p ? "##Some Text##" : "##Some Other Text##") }
' file
a 2021-08-12 14:42:21.0
b 2021-08-12 14:42:22.0
a 2021-08-12 14:42:22.0
b 2021-08-12 14:42:22.0
b 2021-08-12 14:42:23.0
c 2021-08-12 14:42:54.0
c 2021-08-12 14:42:54.0
##Some Text##
a 2021-08-12 14:43:27.0
b 2021-08-12 14:43:27.0
a 2021-08-12 14:43:28.0
b 2021-08-12 14:43:28.0
b 2021-08-12 14:43:28.0
c 2021-08-12 14:43:59.0
c 2021-08-12 14:44:00.0
##Some Text##
a 2021-08-12 14:44:33.0
b 2021-08-12 14:44:33.0
c 2021-08-12 14:45:06.0
##Some Other Text##
a 2021-08-12 14:45:39.0
b 2021-08-12 14:45:39.0
a 2021-08-12 14:45:40.0
b 2021-08-12 14:45:40.0
b 2021-08-12 14:45:40.0
c 2021-08-12 14:46:11.0
c 2021-08-12 14:46:11.0
##Some Text##
上面的 p
只是一个变量,它保存了 $1 的前一个值,而 pp
保存了 2 行后面的 $1 的值。
以下测试使用 GNU sed
4.8 和 BSD sed
版本 (2005) 由 Apple 在 macOS 上发布。
正如您从 sed
开始的那样,这里有一个 sed
解决方案。我假设您想在以 c
开头的连续两行之后插入您的文本(不确定我是否完全理解您的规格):
sed -E '/^c/{x;/^c/a\
##Some Text##
;x;};h' data.txt
最后的 h
复制保留 space 中的每一行。当一行以 c
开头(匹配 /^c/
)时,我们交换模式 space 和保留 space,如果后者也以 c
开头,我们附加文本;当然我们交换回模式 space 和保持 space.
如果您更喜欢单行命令并且您的 shell 是 bash
:
sed -E $'/^c/{x;/^c/a\\n##Some Text##\n;x;};h' data.txt