假设下面是一个文本文件
abcd abc:
我想搜索abc:并在abcd前面添加#输出
abc:
abcd
#
#abcd abc:
我试过用
sed -e '/abc/ s/^#*/#/' -i file
但不能进行上述动作。
tct7dpnv1#
tac | awk + tac解决方案:
tac | awk + tac
tac file | awk 'p {$0 = "#" $0} {p = (/^abc:/ ? 1 : 0)} 1' | tac #abcd abc:
cigdeys32#
由于您是就地编辑,因此可以使用ed:
ed
printf '%s\n' '/abc:/-1 s/^/#/' w q | ed -s file
使用POSIX sed则更加棘手。一种可能性是:
sed
sed -i ' N /abc:/ { s/^/#/ :a n ba } P D ' file
这两个脚本都假定abc:不能出现在文件的第一行,并且您希望只更改模式第一次出现的上面的行,即使它出现了多次。
laximzn53#
如果你使用的是GNU sed,你可以使用-z选项一次解析整个文件,而不是逐行解析。您的最终命令看起来像这样:
-z
sed -zE 's/[^\n]*\nabc:/#\0/g' file
这里,[\n]*\nabc:匹配任何内容,换行符和abc:,并用#和之前匹配的数据替换它。替换字符串中的\0表示正则表达式完全匹配。
[\n]*\nabc:
\0
1l5u6lss4#
使用任何awk:
$ awk 'NR>1{print (/^abc:/ ? "#" : "") prev} {prev=$0} END{print prev}' file #abcd abc:
3lxsmp7m5#
使用此Perl单行程序,如下例所示:
# Prepare test input: cat > infile <<EOF abcd abc: abc: efgh ijhk abc: EOF perl -i.bak -lne '$prev = $curr; $curr = $_; if ( $curr =~ m{^abc:} ) { $prev = "#$prev"; } if ( $. > 1 ) { print $prev; } if ( eof ) { print $curr; } ' infile # Print the result: cat infile #abcd #abc: abc: efgh #ijhk abc:
请注意,如果当前行以abc:开头,则前一行会被总是注解。Perl一行程序使用以下命令行标志:-e:告诉Perl在行内查找代码,而不是在文件中。-n:一次循环输入一行,默认情况下将其分配给$_。-l:在执行代码之前去掉输入行分隔符(默认情况下"\n"在 *NIX上),并在打印时附加它。-i.bak:就地编辑输入文件(覆盖输入文件)。在覆盖之前,通过在其名称后附加扩展名.bak来保存原始文件的备份副本。如果你想跳过写备份文件,只需使用-i并跳过扩展名。$.:当前输入行号。eof:如果找到文件的结尾,返回1(true)。
-e
-n
$_
-l
"\n"
-i.bak
.bak
-i
$.
eof
参见:
perldoc perlrun
perldoc perlrequick
perldoc perlvar
aiazj4mn6#
使用sed(使用GNU sed和macOS附带的sed进行测试):
sed -n '1{h;d;};/abc:/{x;s/^/#/;x;};{x;p;};${g;p;}' file
说明:sed管理两个数据缓冲区:* 保持空间 * 和 * 模式空间 *。当读取新行时,将其存储在模式空间中。脚本使用这两个空格。
p
1{h;d;}
1
h
d
/abc:/{x;s/^/#/;x;}
x
s/^/#/
{x;p;}
${g;p;}
$
g
注意:这比使用-z选项要复杂一些,但即使源文件包含NUL字符也可以工作,并且避免在内存中存储整个文件,这可能是大文件的问题。注意:如果你的文件包含连续的匹配abc:的行,它们也会被注解。示例:
#foo #abc: #abc: abc: bar
如果这是您想要的,请添加-i标志以进行编辑。
kcrjzv8t7#
这可能对你有用(GNU sed):
sed 'N;s/.*\n.*abc:/#&/;P;D' file
追加下一行,如果该行包含abc:,则在第一行之前插入#。然后打印/删除第一行并重复。注意:如果包含abc:的行位于另一个包含abc:的行之上,则可能会注解该行。
7条答案
按热度按时间tct7dpnv1#
tac | awk + tac
解决方案:cigdeys32#
由于您是就地编辑,因此可以使用
ed
:使用POSIX
sed
则更加棘手。一种可能性是:这两个脚本都假定
abc:
不能出现在文件的第一行,并且您希望只更改模式第一次出现的上面的行,即使它出现了多次。laximzn53#
如果你使用的是GNU
sed
,你可以使用-z
选项一次解析整个文件,而不是逐行解析。您的最终命令看起来像这样:
这里,
[\n]*\nabc:
匹配任何内容,换行符和abc:
,并用#
和之前匹配的数据替换它。替换字符串中的\0
表示正则表达式完全匹配。1l5u6lss4#
使用任何awk:
3lxsmp7m5#
使用此Perl单行程序,如下例所示:
请注意,如果当前行以
abc:
开头,则前一行会被总是注解。Perl一行程序使用以下命令行标志:
-e
:告诉Perl在行内查找代码,而不是在文件中。-n
:一次循环输入一行,默认情况下将其分配给$_
。-l
:在执行代码之前去掉输入行分隔符(默认情况下"\n"
在 *NIX上),并在打印时附加它。-i.bak
:就地编辑输入文件(覆盖输入文件)。在覆盖之前,通过在其名称后附加扩展名.bak
来保存原始文件的备份副本。如果你想跳过写备份文件,只需使用-i
并跳过扩展名。$.
:当前输入行号。eof
:如果找到文件的结尾,返回1(true)。参见:
perldoc perlrun
:如何执行Perl解释器:命令行开关perldoc perlrequick
: Perl regular expressions quick startperldoc perlvar
: Perl predefined variablesaiazj4mn6#
使用
sed
(使用GNUsed
和macOS附带的sed
进行测试):说明:
sed
管理两个数据缓冲区:* 保持空间 * 和 * 模式空间 *。当读取新行时,将其存储在模式空间中。脚本使用这两个空格。-n
选项来抑制自动打印。我们使用p
命令显式打印。1{h;d;}
:如果当前行是第一行(地址1
),我们将其复制到保持空间(h
)并开始新的周期(d
)。/abc:/{x;s/^/#/;x;}
:如果一行(除了第一行)匹配abc:
,我们交换hold和pattern空格(x
),前置一个#
(s/^/#/
)并再次交换(x
)。{x;p;}
:我们交换hold和pattern空间(x
)和print(p
)。${g;p;}
:在阅读最后一行($
)后,我们将保持空间复制到模式空间(g
)并打印(p
)。注意:这比使用
-z
选项要复杂一些,但即使源文件包含NUL字符也可以工作,并且避免在内存中存储整个文件,这可能是大文件的问题。注意:如果你的文件包含连续的匹配
abc:
的行,它们也会被注解。示例:如果这是您想要的,请添加
-i
标志以进行编辑。kcrjzv8t7#
这可能对你有用(GNU sed):
追加下一行,如果该行包含
abc:
,则在第一行之前插入#
。然后打印/删除第一行并重复。注意:如果包含
abc:
的行位于另一个包含abc:
的行之上,则可能会注解该行。