出力を特定の行番号にリダイレクトする

出力を特定の行番号にリダイレクトする

grep特定の行を渡し、keyword出力を既存のファイルの特定の行番号にリダイレクトしたいと思います。

注文する

grep "key" temp_file >> desired.txt

私が必要とするのは、ファイルの特定のgrepped行番号に行を追加できることです。xdesired.txt

ベストアンサー1

実行する手順を正しく設定すると簡単になります。最も重要なことは、過度に競合しないソースファイルのバッファを取得することです。唯一の実際の方法は、別のファイルを使用することです。シェルを使用すると、これは非常に簡単です。

{   head -n "$((num_lines_before_insert))"
    grep key temp_file; sed \$d
}   <<SOURCE_FILE >desired.txt
$(  cat <source_file;echo .)
SOURCE_FILE

したがって、ほとんどのシェルの場合bashおよびは含まれていますが、またははzsh含まれていません)dashyash<<here_documentを取得すると、シェルは固有の名前の一時ファイルを生成して、指定した入力ファイル記述子に配置します${TMPDIR:-/tmp}exec(または基本的に0のみ)- そしてすぐに削除してください。コマンドへの入力として使用される場合名前のないファイル - ファイルシステムへのリンクが残っておらず、完全に消える前にカーネルがクリーンアップされるのを待ちます。これは正しいファイルです。データがディスクのどこかに存在します。(または可能であれば少なくともVFS内でtmpfsそして、カーネルは少なくともファイル記述子を解放するまで作業を続けます。

これは、シェルがheredocの実際のバックアップファイルを取得する限り、一時ファイルの要件を処理する非常に安全で簡単な方法を表します。なぜなら、そのファイルが完全に作成され、読み取り前にすべてのファイルシステム名がわかっているからです。それから。したがって、作業中にそのデータを変調することはできません。

上記のブロックは最初に-を使用して一時ファイルに書き込み、catコマンドの置き換えですべて/末尾の空白行を保持しますecho。これはファイルの末尾に行を追加します。{複合ステートメントでは、}3つのコマンドの出力desired.txt(そのうちの2つはソースファイルの尾から読み取られますhead)と一致するエントリをgrep挿入するコマンドが記録されますkey

これが必要かどうかはわかりません。しかし、このようなシーケンスを使用して、ソースファイルを簡単かつ安全に完全に上書きできることを示すことに関連していると思います。

あなたの殻ならいいえheredocsから実際のファイルをインポートすると、その機能をシミュレートできます。

{   set "$$" "${TMPDIR:-/tmp}" "$@"
    exec <"$2/$(  set  -C
         >"$2/$1" cat  &&
         echo "$1")"  >&1 
    rm -- "$2/$1";shift 2
    head "-n$((before))"
    grep ... keyfile; cat
} <source_file 1<>source_file

...これにより、元に戻せない操作を実行する前に、すべてのファイルが書き込み可能であり、ファイル記述子に安全に割り当てられていることを確認し、すべてのファイルシステムもクリーンアップされます。今後同じことをしてください。

これを証明するために私が実行したテストは次のとおりです。

cd /tmp
set "$$" "${TMPDIR:-/tmp}" "$@"
seq 5000000 >test
printf line\ %s\\n 1 2 3 4 5 >test2
{   exec <"$2/$(  set  -C
         >"$2/$1" cat  &&
         echo "$1")"  >&1 
    rm -- "$2/$1";shift 2
    head -n2500000
    grep 3 test2;cat
} <test 1<>test

最初の2つのファイルが作成されました。 1 つは/tmp/test500 万行番号と命名され、seq2 番目は/tmp/test25 行と命名されました。たとえば...

line 1
line 2
line 3
line 4
line 5

次に、上記のブロックを実行してから...

sed -n '1p;$p;2499999,2500002l' <test
wc -l test

...興味深いことに、これは実際に挿入操作と同じ時間がかかり、次のように印刷されます。

1
2499999$
2500000$
line 3$
2500001$
5000000
5000001 test

仕組みは次のとおりです。

  1. リダイレクト1<>は重要です。標準出力にO_RDWRフラグを設定し、ファイルに書き込む各プロセスがファイルの前の内容を上書きすることを保証します。つまり、ソース/ターゲットファイルが任意の時点で切り捨てられるのではなく、最初から最後まで書き換えられることを意味します。
  2. コマンドの置き換えにより、exec有効な部分をできるだけ早く完了できます。(または私ができることがわかったら)。コマンド内でノクロボさてset、インタラクティブシェルでは、"${TMPDIR:-/tmp}/$$"拡張結果がすでに存在する場合、プロセス全体がすぐに停止しますexec <"${TMPDIR:-/tmp}/"。または、スクリプトはシェルがexecディレクトリをstdinにインポートできないため、意味のあるエラーでスクリプトを終了させることもできます。
  3. コマンド内では、サブコピーはまだ存在しない一時ファイルにコピーされ、cat名前は標準出力に書き込まれます。source_fileecho
  4. すべてのファイルハンドルが新しい一時ファイルとしてexec編集されると、rm unlink()現在残っている唯一の一時ステートメントは割り当てられたばかり<のリダイレクトです。
  5. head250万行を見つけ、source_file最初の250万行を作成します。要点は、両方のファイルで同じオフセットを見つけることです。
    • 新しく作成されたtmpファイルがtmpfsにあり、ソースファイルがディスクにある場合は、I / Oのこの部分がより効率的になる可能性があることに注意してください(ここでI / Oが反転してheadディスクファイルから読み取ってここに書き込む場合)。 ) 高いRAMのファイル。
    • これを行うには、exec <>"$(... head ... <&1 >&0tmpファイルを読み書き可能にし、可能であれば末尾に行数を指定するためにhead使用する必要があります。tailこの場合、数字が正確である必要はありません。リング同様に、過渡入力 - 一度に少しずつオフセットを進めます。シェルの組み込み関数をread使用してEOFをテストしたり、wcループを開くために使用できます。
    • これは、EOFが表示されないため、標準入力catにかかる可能性があるためです。<>
  6. grep他のファイルから一部のデータを読み書きすると、source_file他の場所から読み取ったのと同じバイト数だけが上書きされます。
  7. catgrepstdinの残りの部分をstdoutに書き込むことによって生じる可能性がある違いを修正してください1<>source_file

おすすめ記事