ファイルの先頭に行/テキストを追加する方法

ファイルの先頭に行/テキストを追加する方法

次のサンプルファイルがあります。

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)高性能のための普遍的な方法はありません。プレフィックス/etc/servicesデータをファイルに保存して(b)ファイルを編集できないようです。それ頻繁に。


ややクリーンな構文(実際にコーディングした方法):

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

services以下は、最初の内容全体が正確に一致するかどうかをバイト単位で確認しheader、一致しない場合はその内容header全体を前に追加し、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

cmpGNUの "-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。 Macではsed使用する必要が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

同じ結果を得てください。

関連情報