使用 sed 命令检查特定行是否存在,如果不存在,则添加它

使用 sed 命令检查特定行是否存在,如果不存在,则添加它

我想向文件中添加更多终端/etc/securetty。更具体地说,我想添加pts/n, wheren位于范围内0-9(如果不存在)。这可以通过sed命令实现吗?我的内容如下/etc/securetty

# Local X displays (allows empty passwords with pam_unix's nullok_secure)
pts/0
pts/1
pts/2
pts/3

我尝试过类似的事情:

sudo sed '+pts/3+a pts/4' /etc/securetty

这给出了以下错误:

sed: -e expression #1, char 3: extra characters after command

答案1

当我们遇到相应的线时,我们记下分数/数字。该-p选项将autoprint行。当我们到达时,eof我们提取哈希值%h并将其通过grep过滤器传递,以确定哪些终端没有打印,然后我们使用map它来准备格式。

perl -lpe 'm|^pts/([0-9])$| and $h{$1}++;
   END{ print for map { "pts/$_" } grep { !$h{$_} } 0 .. 9; }
' /etc/securetty

我们hold space用数字 0 1 2 ... 9 初始化。每当我们遇到这条pts/[0-9]线时,我们就从保留空间中剪掉它。在 处eof,我们获取保留空间,如果找到任何数字,则应将其修改为正确的格式并打印出来。

sed -e '
   # initialize the hold space with 0 1 ... 9
   1{x;s|.*|'"$(echo {0..9})"'|;x}

   # whatever be the line, it needs to be printed
   p

   # we meet a valid pts/ line
   \|^pts/[0-9]$|{
      # the hold space gets appended to the pattern space
      G
      # grab what is the pts number and search for it in the hold and
      # delete itand store back the changes into hold space.
      s|^pts/\([0-9]\)\n\(.*\)\1 |\2|;h
   }

   # weve not arrived at the eof and weve processed the input so go no further
   $!d

   # we are at the eof, so we bring back the hold space. just in case all
   # numbers were dealt with up, we simply bail out. Else, prepend the str 
   # pts/ to the numbers present and simply were home
   g;/[0-9]/!d;s/ //g
   s|[0-9]|pts/&\n|g;s/.$//

   # *TIP*: Sprinkle the l, list pattern space at various places to see 
   # whats going on.

' /etc/securetty 

答案2

要在丢失时添加单行,可以通过删除每个出现并将其附加到末尾来完成:

sed -n '/pattern/!p;$a pattern'

但重复 10 个模式就很糟糕了。

sed '/pts\/[0-9]/d;$a pts/0 ...

如果要删除最后一行将会失败。所以反过来说,假设第一行是唯一以 开头的行#

sed '/#/a pts/0\
pts/1\
pts/2\
pts/3\
pts/4\
pts/5\
pts/6\
pts/7\
pts/8\
pts\9
/pts\/[0-9]/d'

可恶的。我建议在这种情况下使用不同的工具。

答案3

删除任何/所有pts/N行,然后将它们全部添加回:

{ grep -xv '^pts/[0-9]$' /etc/securetty; printf 'pts/%d\n' {0..9}; } > /etc/securetty.new
cat /etc/securetty.new
mv /etc/securetty.new /etc/securetty

您也可以使用您最喜欢的文本处理工具一次性完成此操作,例如ed

ed -s /etc/securetty <<IN
g/^pts\/[0-9]$/d
.r ! printf pts/\%d\\\n {0..9}
,p
q
IN

(替换,pw就地编辑)或sed

{ printf '%s\\\n' '$a' pts/{0..8}
printf '%s\n' 'pts/9' '/^pts\/[0-9]$/d'
} | sed -f- /etc/securetty

这与普通的几乎相同

sed '$a\
pts/0\
pts/1\
pts/2\
pts/3\
pts/4\
pts/5\
pts/6\
pts/7\
pts/8\
pts/9
/^pts\/[0-9]$/d' /etc/securetty

(使用sed -i就地编辑文件)

答案4

sed逐行处理文件,很难让它“记住”跨行的任何信息。

您可以使用grep来查明文件是否包含给定模式;使用-f,您可以同时提供多个模式。以下生成完整列表pts/0.. pts/9,然后删除给定文件中已存在的模式,并将剩余的模式添加到文件中:

#!/bin/bash
printf 'pts/%d\n' {0..9} \
| grep -vFf "$1"  - >> "$1".new
mv "$1".new "$1"

相关内容