如何将行/文本添加到文件的开头

如何将行/文本添加到文件的开头

我们有以下示例文件:

tcpmux          1/tcp                           # TCP port service multiplexer
tcpmux          1/udp                           # TCP port service multiplexer
rje             5/tcp                           # Remote Job Entry
rje             5/udp                           # Remote Job Entry
echo            7/tcp
echo            7/udp
discard         9/tcp           sink null
discard         9/udp           sink null
systat          11/tcp          users
systat          11/udp          users
daytime         13/tcp
daytime         13/udp
qotd            17/tcp          quote
qotd            17/udp          quote
msp             18/tcp                          # Message send protocol (historic)
msp             18/udp                          # Message send protocol (historic)
chargen         19/tcp          ttytst source
chargen         19/udp          ttytst source

我们如何将以下行附加到文件的开头?

# The latest IANA port assignments can be gotten from
#       http://www.iana.org/assignments/port-numbers
# The Well Known Ports are those from 0 through 1023.
# The Registered Ports are those from 1024 through 49151
# The Dynamic and/or Private Ports are those from 49152 through 65535
#
# Each line describes one service, and is of the form:
#
# service-name  port/protocol  [aliases ...]   [# comment]

这样该文件将如下所示:

# The latest IANA port assignments can be gotten from
#       http://www.iana.org/assignments/port-numbers
# The Well Known Ports are those from 0 through 1023.
# The Registered Ports are those from 1024 through 49151
# The Dynamic and/or Private Ports are those from 49152 through 65535
#
# Each line describes one service, and is of the form:
#
# service-name  port/protocol  [aliases ...]   [# comment]
tcpmux          1/tcp                           # TCP port service multiplexer
tcpmux          1/udp                           # TCP port service multiplexer
rje             5/tcp                           # Remote Job Entry
rje             5/udp                           # Remote Job Entry
echo            7/tcp
echo            7/udp
discard         9/tcp           sink null
discard         9/udp           sink null
systat          11/tcp          users
systat          11/udp          users
daytime         13/tcp
daytime         13/udp
qotd            17/tcp          quote
qotd            17/udp          quote
msp             18/tcp                          # Message send protocol (historic)
msp             18/udp                          # Message send protocol (historic)
chargen         19/tcp          ttytst source
chargen         19/udp          ttytst source

简单的解决方案是将原始文件复制到file.bck,将新行追加到文件中,然后追加file.bck到文件中。

但这不是一个优雅的解决方案。

答案1

相对优雅的解决方案使用POSIX指定文件编辑器ex——至少在这个意义上是优雅的这将处理任何任意内容而不是依赖于特定的格式(尾部反斜杠)或特定的格式缺失。

printf '0r headerfile\nx\n' | ex file-with-contents

这将打开file-with-contents,读入最顶部ex的完整内容,然后将修改后的缓冲区保存回。headerfilefile-with-contents

如果性能是一个严重问题并且文件很大,这可能不是适合您的方法,但是(a)没有高性能的通用方法前置将数据保存到文件中,并且 (b) 我不认为您会编辑您的/etc/services文件经常。


稍微干净一点的语法(我实际编码的方式):

printf '%s\n' '0r headerfile' x | ex file-with-contents

接下来是一段更复杂但收敛的代码,它将逐字节检查 的开头是否services完全匹配 的整个内容header,如果不匹配,则将在前面添加headerto的整个内容services并保存更改。

这完全符合 POSIX 标准。

dd if=services bs=1 count="$(wc -c < header)" 2>/dev/null |
  cmp -s - header ||
    printf '%s\n' '0r header' x |
      ex services

一个更简单的版本,使用 GNUcmp的“-n”选项:

cmp -sn "$(wc -c <header)" header services ||
  printf '%s\n' '0r header' x | ex services

当然,这些都不够智能,无法检查部分匹配,但这远远超出了简单的一行的能力,因为本质上会涉及猜测。

答案2

通常,你就是这样做的。在文件中添加行很困难,因为文件只是字节序列,因此您需要将现有数据向前移动以为新数据腾出空间,并且没有直接的方法(至少没有标准方法)。理论上,人们可能会想象一个基于可变长度记录的文件系统,您可以在开始处或现有记录之间添加新记录,但这并不是它在实践中的工作方式。

某些文件系统可以移动数据块,但它们是固定大小的块,因此对于行长度可变的文本文件没有多大用处。

即使您执行类似sed -i或 之类的操作perl -i,他们也会出于这个原因在幕后创建一个临时文件。

所以,无论优雅与否,我都会选择:

cat prefix data > data.new && mv data.new data

对于几行,您可以使用(在 GNU sed 中):

sed -i.bak -e '1i first prefix line' -e '1i second prefix line'  data

但是生成插入命令或为要添加的每一行添加反斜杠也不是很优雅。

答案3

好吧,我决定除了评论之外写一个答案。

您可以使用类似i的命令sed

sed -i '1i \
# The latest IANA port assignments can be gotten from\
#       http://www.iana.org/assignments/port-numbers\
# The Well Known Ports are those from 0 through 1023.\
# The Registered Ports are those from 1024 through 49151\
# The Dynamic and/or Private Ports are those from 49152 through 65535\
#\
# Each line describes one service, and is of the form:\
#\
# service-name  port/protocol  [aliases ...]   [# comment]' file

这是针对 GNU 的sed。对于sedMac,您需要使用sed -i '' -e ...,而对于 POSIX,sed没有简单的方法可以就地完成操作。

答案4

另一种方法:sponge使用更多实用程序大多数 Linux 发行版中都提供了软件包,您也可以这样做

$ cat - file.txt | sponge file.txt
# The latest IANA port assignments can be gotten from
#       http://www.iana.org/assignments/port-numbers
# The Well Known Ports are those from 0 through 1023.
# The Registered Ports are those from 1024 through 49151
# The Dynamic and/or Private Ports are those from 49152 through 65535
#
# Each line describes one service, and is of the form:
#
# service-name  port/protocol  [aliases ...]   [# comment]

这用于cat组合重现标准输入 ( -) 和原始文件 ( file.txt),并将组合输出通过管道传输到sponge,然后将结果就地写回同一文件。然后,将标头粘贴到终端中并以 结束Ctrl+D

或者,如果您已经将标头存储在单独的文件中,则可以使用

cat header.txt file.txt | sponge file.txt

达到同样的结果。

相关内容