在shell脚本中搜索行的上方添加注解

vlf7wbxs  于 2023-05-01  发布在  Shell
关注(0)|答案(7)|浏览(340)

假设下面是一个文本文件

abcd
abc:

我想搜索abc:并在abcd前面添加#
输出

#abcd
abc:

我试过用

sed -e '/abc/ s/^#*/#/' -i file

但不能进行上述动作。

tct7dpnv

tct7dpnv1#

tac | awk + tac解决方案:

tac file | awk 'p {$0 = "#" $0} {p = (/^abc:/ ? 1 : 0)} 1'  | tac

#abcd
abc:
cigdeys3

cigdeys32#

由于您是就地编辑,因此可以使用ed

printf '%s\n' '/abc:/-1 s/^/#/' w q | ed -s file

使用POSIX sed则更加棘手。一种可能性是:

sed -i '
    N
    /abc:/ {
        s/^/#/
        :a
        n
        ba
    }
    P
    D
' file

这两个脚本都假定abc:不能出现在文件的第一行,并且您希望只更改模式第一次出现的上面的行,即使它出现了多次。

laximzn5

laximzn53#

如果你使用的是GNU sed,你可以使用-z选项一次解析整个文件,而不是逐行解析。
您的最终命令看起来像这样:

sed -zE 's/[^\n]*\nabc:/#\0/g' file

这里,[\n]*\nabc:匹配任何内容,换行符和abc:,并用#和之前匹配的数据替换它。替换字符串中的\0表示正则表达式完全匹配。

1l5u6lss

1l5u6lss4#

使用任何awk:

$ awk 'NR>1{print (/^abc:/ ? "#" : "") prev} {prev=$0} END{print prev}' file
#abcd
abc:
3lxsmp7m

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)。

参见:

aiazj4mn

aiazj4mn6#

使用sed(使用GNU sed和macOS附带的sed进行测试):

sed -n '1{h;d;};/abc:/{x;s/^/#/;x;};{x;p;};${g;p;}' file

说明: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:的行,它们也会被注解。示例:

#foo
#abc:
#abc:
abc:
bar

如果这是您想要的,请添加-i标志以进行编辑。

kcrjzv8t

kcrjzv8t7#

这可能对你有用(GNU sed):

sed 'N;s/.*\n.*abc:/#&/;P;D' file

追加下一行,如果该行包含abc:,则在第一行之前插入#。然后打印/删除第一行并重复。
注意:如果包含abc:的行位于另一个包含abc:的行之上,则可能会注解该行。

相关问题