まだ診断されていないアプリケーションエラーのため、ディスクがいっぱいの数百台のサーバーがあります。重複した行がいっぱいのファイルがあります。ログファイルではなく、変数定義を含むユーザー環境ファイルです(ファイルを削除することはできません)。
誤って追加された行を確認して削除する簡単なコマンドを作成し、sed
ファイルのローカルコピーでテストしました。期待どおりに動作します。
ただし、ディスクがいっぱいのサーバーで試してみると、次のようなエラーが発生します(コピーして貼り付けるのではなく、メモリで発生したエラーです)。
sed: couldn't flush /path/to/file/sed8923ABC: No space left on deviceServerHostname
当然私知る残りのスペースはありません。だからものを削除しようとしています! (sed
私が使用したコマンドは、4000行以上のファイルを約90行に減らしました。)
私のsed
コマンドはただsed -i '/myregex/d' /path/to/file/filename
ディスクがいっぱいになったときにこのコマンドを適用する方法はありますか?
(迅速な修正で数百台のサーバーに適用する必要があるため、自動化する必要があります。)
(当然、アプリケーションエラーを診断する必要がありますが、その間にサーバーが機能していません...)
修正する:削除される可能性がある他のアイテムを削除すると解決される状況がありましたが、それでも答えを望んでいます。これ質問、これは将来と他の人に役立ちます。
/tmp
それは動作しません。同じファイルシステムにあります。
ディスク容量を解放する前にテストを実行した結果、ファイルを開いて実行してから、vi
ファイルの行を削除できることがわかりました。別のファイルシステムに頼らずに自動的にこれを行うことが可能になりそうです。一時ファイルを保管してください.... ....(?):g/myregex/d
:wq
答え1
この-i
オプションは実際に元のファイルを上書きしません。出力として新しいファイルを作成し、元のファイル名に名前を変更します。ファイルシステムにこの新しいファイルのスペースがないため失敗します。
これはスクリプトで直接実行する必要がありますが、別のファイルシステムに新しいファイルを作成する必要があります。
または、正規表現に一致する行を削除する場合に使用できgrep
ますsed
。
grep -v 'myregex' /path/to/filename > /tmp/filename && mv /tmp/filename /path/to/filename
通常、プログラムが入力と出力に同じファイルを使用することはほとんど不可能です。ファイルの書き込みを開始すると、プログラムが読み取るファイルの部分に元のコンテンツが表示されなくなります。したがって、最初に元のファイルをどこかにコピーするか、新しいファイルを作成して完了したら名前を変更する必要があります。
一時ファイルを使用したくない場合は、ファイルの内容をメモリにキャッシュしてみてください。
file=$(< /path/to/filename)
echo "$file" | grep -v 'myregex' > /path/to/filename
答え2
それがsed
うまくいく方法です。-i
(内部編集)と一緒に使用すると、sed
処理されたファイルの新しい内容を含む一時ファイルが作成されます。完了したら、sed
現在の作業ファイルを一時ファイルに置き換えます。ユーティリティはファイルを編集しません。所定の位置に。これがすべての編集者がすることです。
これはシェルで次のことを行ったのと同じです。
sed 'whatever' file >tmp_file
mv tmp_file file
この時点でsed
システムコールを使用して、バッファリングされたデータをエラーメッセージに記載されているファイルにフラッシュしてみてくださいfflush()
。
出力ストリームの場合、
fflush()
ストリームの基本書き込み機能によって、指定された出力または更新ストリームのすべてのユーザー空間バッファリングデータを強制的に書き込みます。
あなたの問題に対する解決策があります。別のファイルシステムをマウントして(tmpfs
たとえば、十分なメモリがあるか、外部ストレージデバイスがある場合)、一部のファイルをそこに移動して処理してから再度移動します。
答え3
ex
この質問を投稿した後、これがPOSIX互換プログラムであることがわかりました。ほぼ普遍的にシンボリックリンクされていますが、vim
どちらにしても(私の考えでは)ex
ファイルシステムに関連する重要なポイントです(POSIX仕様から得られます)。
このセクションで使用される用語バッファの編集現在の作業テキストを説明してください。この用語は特定の実装を意味しません。すべての編集変更は編集バッファで行われ、エディタコマンドへの変更はファイルに書き込まれるまでファイルには影響しません。
「……影響を及ぼすだろうどのファイル..."ファイルシステムに何か(一時ファイルを含む)を置くことは、"すべてのファイルに影響を与えると見なされます。 「おそらく?*
一生懸命勉強したPOSIX仕様ex
ex
特定のコマンドが散在しているオンラインで見られる一般的なスクリプト使用vim
と比較して、移植可能な用途に関するいくつかの「問題」が指摘されています。
+cmd
POSIXによると、実装はオプションです。- 複数の
-c
オプションを許可することもオプションです。 - グローバルコマンドは、
:g
エスケープされていない次の改行まですべてを「食べます」(したがって、最後から1回ではなく、正規表現について見つけた各一致の後に実行されます)。だから-c 'g/regex/d | x'
削除することしかできません。一つインスタンスを作成し、ファイルを終了します。
だから私が調査したところによると、特定の正規表現に一致するすべての行を削除するために、ファイルシステム全体でファイルを内部で編集するPOSIX互換の方法は次のとおりです。
ex -sc 'g/myregex/d
x' /path/to/file/filename
ファイルをバッファにロードするのに十分なメモリがある場合、この方法は機能します。
*その他の注意事項を発見したらコメントでお知らせください。
答え4
他の回答で述べたように、
sed -i
ファイルを新しいファイルにコピーして機能します。同じディレクトリに、変更を実行し、新しいファイルを元のファイルの上に移動します。それがうまくいかない理由です。 (Original Line Editor)はやや似ていますが、前回確認したときに一時ファイルed
用でした。ファイルシステムがいっぱいのシステムと異なる
/tmp
場合は、これを実行できます。/tmp
ed
次のことを試してください(対話型シェルプロンプトから):
$編集/パス/ターゲット/ファイル/ファイル名 人 G/正規表現/D 勝つ キュー
(P
これは首都P)必ずしも必要ではありません。プロンプトをオンにしないと、暗闇の中で作業することになり、一部の人々はこれを不快に思っています。そしてw
うんq
勝つ意識とキューそれ。
ed
神秘的な診断で有名です。いつでも*
プロンプト以外の内容や操作が成功したことを明確に確認する内容(例:特に?
)が含まれている場合欲しくないファイルに書き込む(使用されているw
)ちょうどあきらめます(q
)。それでも心がほぐれない場合は、q
もう一度教えてください。
/tmp
ディレクトリがいっぱいのファイルシステムにある場合(またはそのファイルシステムがいっぱいの場合)、どこかでスペースを探します。 Chaosでは、tmpfsまたは外部ストレージデバイス(フラッシュドライブなど)のマウントについて言及しています。ただし、ファイルシステムが複数あり、そうでない場合みんな完了すると、他の既存のもののいずれかを簡単に使用できます。 Chaosはファイルを別のファイルシステムにコピーし、そこで編集(使用sed
)してから再コピーすることをお勧めします。現時点では、これはおそらく最も簡単な解決策です。ただし、別のアプローチでは、空き領域があるファイルシステムに書き込み可能なディレクトリを作成し、そのTMPDIR
ディレクトリを指すように環境変数を設定しますed
。何でも害を及ぼす。)
作業を開始したら、ed
次のようにして自動化できます。
編集するファイル名<< ターミネーター G/正規表現/D 勝つ キュー EOF
スクリプトから。またはdon_crisstiの提案に従ってください。printf '%s\n' 'g/myregex/d' w q | ed -s filename