このインプレース行の削除は危険すぎるdd
と考えられるため、ファイル システム呼び出しをかなりきめ細かく制御できる別の方法が必要です。私の最初の衝動は、c で何かを書きたいということですが、可能ではありますが、それは少しやり過ぎだと思います。代わりに、一般的なスクリプト (シェル スクリプトではない) 言語に目を向ける価値があります。これらの言語には通常、かなり単純な方法でファイル syscall にマップされるかなり低レベルのファイル API があるためです。これは、python、perl、Tcl、または利用可能な他の多くのスクリプト言語のいずれかを使用して実行できると思います。私はTclに最も精通しているので、ここに行きます:
#!/bin/sh
# \
exec tclsh "$0" "$@"
package require Tclx
set removeline [lindex $argv 0]
set filename [lindex $argv 1]
set infile [open $filename RDONLY]
for {set lineNumber 1} {$lineNumber < $removeline} {incr lineNumber} {
if {[eof $infile]} {
close $infile
puts "EOF at line $lineNumber"
exit
}
gets $infile line
}
set bytecount [tell $infile]
gets $infile rmline
set outfile [open $filename RDWR]
seek $outfile $bytecount start
while {[gets $infile line] >= 0} {
puts $outfile $line
}
ftruncate -fileid $outfile [tell $outfile]
close $infile
close $outfile
私の特定のボックスには Tcl 8.4 があることに注意してください。したがって、ftruncate コマンドを使用するには Tclx パッケージをロードする必要がありました。Tcl 8.5 では、chan truncate
代わりに使用できるものがあります。
削除する行番号とファイル名をこのスクリプトに渡すことができます。
つまり、スクリプトは次のことを行います。
- ファイルを読み取り用に開く
- 最初の n-1 行を読む
- 次の行 (行 n) の開始位置のオフセットを取得します
- n 行目を読む
- 書き込み用に新しい FD でファイルを開きます
- 書き込み用 FD のファイルの場所を n 行目の先頭のオフセットに移動します
- 読み取りFDから残りの行を読み取り続け、読み取りFD全体が読み取られるまで書き込みFDに書き込みます
- 書き込みFDを切り捨てる
ファイルはその場で正確に編集されます。一時ファイルは使用されません。
これは、必要に応じて python や perl などで書き直すことができると確信しています。
アップデート
上記の Tcl スクリプトと同様の手法を使用して、ほぼ純粋な bash でインプレース行削除を実行できます。truncate
ただし、大きな注意点は、コマンドを使用できるようにする必要があるということです。Ubuntu 12.04 VM にはありますが、古い Redhat ベースのボックスにはありません。スクリプトは次のとおりです。
#!/bin/bash
n=$1
filename=$2
exec 3<> $filename
exec 4<> $filename
linecount=1
bytecount=0
while IFS="" read -r line <&3 ; do
if [[ $linecount == $n ]]; then
echo "omitting line $linecount: $line"
else
echo "$line" >&4
((bytecount += ${#line} + 1))
fi
((linecount++))
done
exec 3>&-
exec 4>&-
truncate -s $bytecount $filename
#### or if you can tolerate dd, just to do the truncate:
# dd of="$filename" bs=1 seek=$bytecount count=0
#### or if you have python
# python -c "open(\"$filename\", \"ab\").truncate($bytecount)"
最後に部分的な切り捨てを行い、この回答を完成させるためのより一般的な(bashのみの?)方法を知りたいです。もちろん、切り捨ても同様に実行できますがdd
、以前の回答ではすでに除外されていたと思います。
記録のために、このサイトには、さまざまな言語でインプレース ファイルの切り捨てを行う方法がリストされています。これらのいずれかが環境で使用される場合に備えて。