処理する必要がある大きなファイルがあり、適切に機能していないように見えるスクリプトをいくつか書き込んだ後、ファイル内の行の小さなサブセットがタブ区切りではなく実際にスペース区切りになっていることがわかりました。
質問:スペースで区切られたこれらの行をタブで区切られた行に変更するための最良の方法は何でしょうか?
ファイルの各行には4つのエントリがあり、合計約5000のエントリがあり、そのうちの約150はタブ区切りではなくスペースで区切られています。
tr ' ' '\t' < file 1<> file
すべてのスペース文字をタブ文字に置き換えます。
安全ではないと言っている人に応答するだけです。
シェルは、ファイル記述子0の読み取り、およびファイル記述子1の読み取りと書き込みのためにファイルを開きます。これらのいずれかが失敗した場合は、救済され、tr
も実行されません。リダイレクトが成功すると、tr
が実行されます。
tr
は、一度に1ブロックずつファイルを読み取り、文字変換を行い、変更されていないブロックの上に変更されたブロックを出力します。
そうすることで、通常はディスクにスペースを割り当てる必要がなくなります。これの例外は、ファイルが最初にまばらだった場合、またはコピーオンライトを実装するファイルシステムの場合です。したがって、「使用可能なスペースがない」というエラーは起こりません。
他のエラーは、下のディスクに障害が発生した場合、またはファイルシステムがシンプロビジョニングされたブロックデバイス(LVMスナップショットなど)にある場合のI/Oエラーなど、発生する可能性があります。バックアップをバックアップします。
いずれの場合でも、write()
システムコールが失敗すると、tr
はエラーを報告して終了します。 stdoutは読み取り/書き込みモードで開いているため、切り捨てられません。ファイルが切り捨てられるためには、tr
は、終了時に標準出力でtruncate()
を明示的に呼び出す必要がありますが、これは意味がありません。
ただし、ファイルが部分的に音訳される(tr
が失敗するところまで)ことになります。
私が見つけたのは、GNU tr
は現在Debian sid AMD64で見つかっています bug があり、write()
stdoutでのシステムコールと出力のガベージ(edit、現在 libc6 Debianパッケージのバージョン2.19-1以降で修正 )これは実際にファイルを破壊します(ただし、ファイルを切り捨てません)。
tr ' ' '\t' < file > newfile && mv newfile file
file
は正しく作成されているが、それに関連する多くの問題がない限り、newfile
は置き換えられません。
newfile
を上書きしないようにする必要があります(シンボリックリンクも考えてください)tr ' ' '\t' < file 1<> file
は、一般的に使用されているPerl -pi -e 's/ /\t/g'
より安全です。これは、Perl
が失敗すると(ディスクがいっぱいの場合など)、元のファイルが失われ、Perl
が管理しているファイルのみが取得されるためです。これまでに出力します。
sed
も使用できます。
sed -i.bak 's/ /\t/g' filename
これにより、filename.bak
ファイルを編集する前。
s/ /\t/g
=>これは、sed
に、ファイルの各行全体でスペースをタブ文字で置き換えるように指示します。
ファイル内のすべてのスペースをタブに変更するには、tr
を使用します。
tr ' ' '\t' <input_file >output_file
1つ以上のスペースのすべてのシーケンスを1つのタブに変更するには、sed
を使用します。
sed -e 's/ */\t/g' <input_file >output_file
Sedの実装には、\t
がタブを意味するものと理解しているものもあれば、文字どおりのタブ文字が必要なものもあります。
可変数のスペースを使用して列を整列する整列された列を含むファイルがある場合、それを unexpand
でタブ区切りの列に変換できます。