IOリダイレクトとヘッドコマンド

IOリダイレクトとヘッドコマンド

今日私はCygwin bashシェルでファイルをすばやく編集しようとしましたが、.hgignore間違った行を追加しました。これが最善のアプローチであるかどうかはわかりませんが、head -1 .hgignore問題のある行を削除する方法をすばやく考えました(以前はファイルに1行しかありませんでした)。もちろん、実行されると、最初の行は唯一の出力として提供されます。

ただし、出力をリダイレクトしてrewrite fileを使用しようとすると、head -1 .hgignore > .hgignoreファイルは空です。なぜこれが起こるのですか?貼り付けようとするとhead -1 .hgignore >> .hgignore正しく貼り付けられますが、明らかに望ましい結果ではありません。この場合、切り捨てられたリダイレクトが機能しないのはなぜですか?

答え1

私の考えでは、ブルースが答えると思います。ここで何が起こっていますか?ハウジング配管付き。

私が好きな小さなユーティリティの1つspongeその他のユーティリティ。ターゲット出力ファイルを開いてデータを書き込む前に、利用可能なすべての入力を「シンク」してこの問題を解決します。これにより、意図したとおりに正確にパイプラインを作成できます。

$ head -1 .hgignore | sponge .hgignore

貧しい人々の解決策は、出力を一時ファイルにパイプし、パイプが完了した後(たとえば、次の実行コマンド)、一時ファイルを元のファイルの場所に戻すことです。

$ head -1 .hgingore > .hgignore.tmp
$ mv .hgignore{.tmp,}

答え2

シェルが次のコマンドラインを受け取ると、command > file.outシェル自体はというファイルを開きます(作成することもできます)file.out。シェルは、ファイル記述子 0 を開いて取得したファイル記述子に設定します。これがI / Oリダイレクトが機能する方法です。各プロセスは、ファイル記述子0、1、2について知っています。

最も難しい部分はどのように開いているfile.out。ほとんどの場合、file.out書き込みのためにオフセット0(つまり切り取り)で開くことを望みます。これはシェルが実行する操作です。 .hgignoreを切り取り、書き込み用に開き、ファイル記述子を0にコピーしてexecを実行しますhead。即時ファイル破損。

Bashシェルでは、set noclobber次のようにしてこの動作を変更できます。

答え3

存在する

head -n 1 file > file

filehead始める前に切り捨てましたが、書いている場合:

head -n 1 file 1<> file

file読み書きモードでは開かれません。ただしhead、書き込みが完了するとファイルが切り捨てられないため、上記の行は機能しません(head最初の行自体のみが書き換えられ、他の行は変更されていません)。

ただし、head戻ってからfdまだ開いている間は別の実行を呼び出すことができますtruncate

たとえば、

{ head -n 1 file; perl -e 'truncate STDOUT, tell STDOUT'; } 1<> file

ここで重要なのは、truncate上記の内容がheadファイルの最初の行からfd 1にカーソルを移動するだけです。私たちに必要ではない最初の行を書き換えますが、そこには何の害もありません。

POSIX ヘッダーを使用すると、最初の行を書き換えることなく実際に外れることができます。

{ head -n 1 > /dev/null
  perl -e 'truncate STDIN, tell STDIN'
} <> file

headここでは、標準入力でカーソル位置を移動するという事実を使用します。通常、head入力をチャンクで読み取るとパフォーマンスが向上しますが、POSIXでは可能であればseek最初の行を超えるとすぐに返す必要があります。ただし、すべての実装がこれを行うわけではありません。

readまたは、この場合はシェルのコマンドを使用できます。

{ read -r dummy; perl -e 'truncate STDIN, tell STDIN'; } <> file

答え4

ExモードでVimを使用できます。

ex -sc '2,d|x' .hgignore
  1. 2,2行目を最後まで選択してください。

  2. d削除

  3. x保存して閉じる

関連情報