查找、替换或插入 - 命令行

Find, Replace or Insert - command Line

我有一个类似的列表:

What do you want to do?
Import a text file by opening it in Excel
Import a text file by connecting to it
Export data to a text file by saving it
Change the delimiter that is used in a text file
Change the separator in all .csv text files

使用 SED 我可以在 'connecting' 上找到匹配项并替换行:

 sed 's^.*connecting.*^Import a text file by opening it^g' crontab

这应该将上面的列表更改为:

What do you want to do?
Import a text file by opening it in Excel
Import a text file by opening it
Export data to a text file by saving it
Change the delimiter that is used in a text file
Change the separator in all .csv text files

然而我需要做的是:

如果存在包含单词 connecting 的行,则替换该行, 如果该行不存在,则将其作为新行添加到列表的末尾。

我知道我可以 echo "Import a text file by opening it" >> list 将行添加到列表的末尾,但是无论如何我可以在一个命令中完成吗?或者在一个实例中可以是 运行 的命令?

谢谢

您可以尝试 , with similar regex syntax than ,但对于这些问题来说要强大得多。它只是在至少完成一次替换时设置一个标志。解析完整个文件后,在 END {} 块中,如果 $flag 变量未设置,则添加注释:

perl -pe '
    s/^.*connecting.*$/Import a text file by opening it/ and $done = 1;
    END { printf qq|%s\n|, q|Import a text file by opening it| unless $done }
' infile

找到该行后,它会产生:

What do you want to do?
Import a text file by opening it in Excel
Import a text file by opening it
Export data to a text file by saving it
Change the delimiter that is used in a text file
Change the separator in all .csv text files

当找不到时,它产生:

What do you want to do?
Import a text file by opening it in Excel
Export data to a text file by saving it
Change the delimiter that is used in a text file
Change the separator in all .csv text files
Import a text file by opening it

如果出现不止一次,请更改两者但不附加任何内容:

What do you want to do?
Import a text file by opening it in Excel
Import a text file by opening it
Export data to a text file by saving it
Change the delimiter that is used in a text file
Import a text file by opening it
Change the separator in all .csv text files

一个简单的方法是使用 awk:

awk 'BEGIN { s = "Import a text file by opening it" } /connecting/ { [=10=] = s; n = 1 } 1; END { if(!n) print s }' filename

工作原理如下:

BEGIN {                                    # Before anything else:
  s = "Import a text file by opening it"   # Remember the string by a shorter
                                           # name so we don't have to repeat it
}
/connecting/ {                             # If a line contains "connecting",
  [=11=] = s                                   # replace the line with that string
  n = 1                                    # and raise a flag that we've done so.
}
1                                          # print
END {                                      # in the end:
  if(!n) {                                 # If the string wasn't yet printed,
    print s                                # do it now.
  }
}

或者,您可以使用 sed 的保持缓冲区。例如:

sed '1 { x; s/.*/Import a text file by opening it/; x; }; /connecting/ { s/.*//; x; }; $ { G; s/\n$//; }' filename

其工作原理如下:

1 {                                        # while processing the first line
  x                                        # swap hold buffer, pattern space
  s/.*/Import a text file by opening it/   # write text to pattern space
  x                                        # swap back.
}                                          # Now the hold buffer contains the
                                           # line we want to insert, and the
                                           # pattern space the first line.

/connecting/ {                             # For all lines: If a line contains
                                           # "connecting"
  s/.*//                                   # empty the pattern space
  x                                        # swap in hold buffer.
                                           # If this happened, the hold buffer
                                           # will be empty and the pattern space
                                           # will contain "Import a ..."
}
$ {                                        # Last line:
  G                                        # Append hold buffer to pattern space.
                                           # If the hold buffer is empty (i.e.,
                                           # was used somewhere else), this
                                           # appends a newline, so
  s/\n$//                                  # remove it if that happened.
}

注意 sed 代码取决于只有一行包含 "connecting." 如果有更多这样的行,它们将被替换为空行,因为保持缓冲区是空的当第二行出现时。可以处理这种情况,但您必须决定其中应该发生什么。既然你在评论里回复说只有这样一行,我觉得没必要去猜。