私のプロジェクトでは、ファイルのいくつかの既存のテキストを置き換える必要があります。foo
次のような他のテキストでfooofoo
:
abc.txt
name
foo
foo1
だから私は次のことを試みます:
sed -i "s/foo/fooofoo/g" abc.txt
ただし、次のエラーが発生します。
sed:無効なオプション -
i
マニュアルで以下を使用する必要があることがわかりました。
sed -i\ "s/foo/fooofoo/g" abc.txt
しかし、これも動作しません。
私はperl
andで代替を見つけましたが、awk
Solarisで解決策を見つけることができればsed
幸いです。
私はこのバージョンのbashを使用しています。
GNU bash、バージョン 3.2.57(1)-リリース(sparc-sun-solaris2.10)
答え1
使用ed
。ほとんどのプラットフォームで動作し、ファイルをその場で編集できます。代替パターンに基づく構文は似ている
ため、次のようになります。sed
ed
ed -s infile <<\IN
,s/old/new/g
w
q
IN
答え2
GNU sed をインストールできない場合は、次を使用します。
sed "s/foo/fooofoo/g" abc.txt >abc.tmp && mv abc.tmp abc.txt
これは以下を使用します。リダイレクトsedの出力を一時ファイルに送信します。 sedが正常に完了すると、一時abc.txt
ファイルが上書きされます。
GNU sedのソースコードに見られるように、これがすぐにsed -i
完了したものです。だからこれはsed -i
。
すでに存在する可能性がある場合、または同様のユーティリティを使用して一時ファイルの識別名を生成 abc.tmp
できます。mktemp
答え3
等しいものが欲しいなら、sed -i.bak
とても簡単です。
GNU sed については、次のスクリプトを検討してください。
#!/bin/sh
# Create an input file to demonstrate
trap 'rm -r "$dir"' EXIT
dir=$(mktemp -d)
grep -v '[[:upper:][:punct:]]' /usr/share/dict/words | head >"$dir/foo"
# sed program - removes 'aardvark' and 'aardvarks'
script='/aard/d'
##########
# What we want to do
sed -i.bak -e "$script" "$dir"
##########
# Prove that it worked
ls "$dir"
cat "$dir/foo"
私たちは単にマーカーラインを次のように変更できます。
cp "$dir/foo" "$dir/foo.bak" && sed -e "$script" "$dir/foo.bak" >"$dir/foo"
これにより、既存のファイルがバックアップに移動され、新しいファイルが作成されます。
私たちが等しいことを望むなら
sed -i -e "$script" "$dir" # no backup
これは少し複雑になります。標準入力から読み取るためにファイルを開いてからリンクを解除し、sedの出力にそれを置き換えるように指示できます。
( cp "$dir/foo" "$dir/foo.bak"; exec <"$dir/foo.bak"; rm "$dir/foo.bak"; exec sed -e "$script" >"$dir/foo" )
その後も元の標準入力を引き続き使用できるように、サブシェルでこれを行います。サブシェルなしで入力を切り替えて再切り替えすることは可能ですが、私にとってはこの方法がより明確に見えます。
まず、新しいファイルを作成するよりもコピーするときに注意する必要があることに注意してくださいfoo
。これは、ファイルに複数の名前があり(たとえば、ハードリンクがある場合)、リンクが壊れないようにする場合に重要です。
答え4
使用するsed
かどうか見える一時ファイル:
別々の作成を避けることができます。見える「一時ファイル」:
exec 3<abc.txt
rm abc.txt
sed 's/foo/fooofoo/' <&3 >abc.txt
exec 3<&-
説明する
Unixシリーズシステムは、ファイルが削除されるまでディスクからファイルの内容を実際に削除しません。両方ファイルシステムからリンクを解除し、そしてどのプロセスでも開かれません。したがって、exec 3<
シェルでファイルを開き、ファイルディスクリプタ3 rm
(ファイルシステムから切断)を読み取り、sed
ファイルディスクリプタ3を入力として使用して呼び出すことができます。
これは非常にこれとは異なり、
# Does not work.
sed 's/foo/fooofoo/' <abc.txt >abc.txt
違いは、1つのコマンドでこれを行うと、シェルが読み取りと書き込みのために同じファイルを開き、ファイルを切り捨てるオプションがあることです。ファイルはまだ同じであるため、失われたコンテンツが得られます。ただし、読み取り用に開いてから書き込み用に開き、rm
同じパス名を書き込み用に開くと、実際には同じパス名で新しいファイルが作成されます(ただし、新しいinodeとディスクの場所に元のファイルが残っているため)。 open):コンテンツを引き続き使用できます。
その後、以前に開いたファイル記述子を閉じることができます(exec 3<&-
特殊構文が実行する操作)。これにより、オペレーティングシステムがそのディスク容量を削除(未使用としてマーク)できるように、元のファイルが解放されます。
ガイドライン
このソリューションについて覚えておくべきいくつかの点は次のとおりです。
コンテンツは一度だけ「探索」できます。持ち運べるファイル記述子内でシェルが「見える」方法 - プログラムが何かを読むと、他のプログラムはファイルの残りの部分だけを見ることができます。
sed
ファイル全体を読みます。シェル/スクリプト/sedが完了する前に終了すると、元のファイルが失われる可能性が低くなります。