web-dev-qa-db-ja.com

ファイルの列区切りを変更する

処理する必要がある大きなファイルがあり、適切に機能していないように見えるスクリプトをいくつか書き込んだ後、ファイル内の行の小さなサブセットがタブ区切りではなく実際にスペース区切りになっていることがわかりました。

質問:スペースで区切られたこれらの行をタブで区切られた行に変更するための最良の方法は何でしょうか?

ファイルの各行には4つのエントリがあり、合計約5000のエントリがあり、そのうちの約150はタブ区切りではなくスペースで区切られています。

6
sdf
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が管理しているファイルのみが取得されるためです。これまでに出力します。

8

sedも使用できます。

sed -i.bak 's/ /\t/g' filename

これにより、filename.bakファイルを編集する前。

s/ /\t/g =>これは、sedに、ファイルの各行全体でスペースをタブ文字で置き換えるように指示します。

2
ptierno

ファイル内のすべてのスペースをタブに変更するには、trを使用します。

tr ' ' '\t' <input_file >output_file

1つ以上のスペースのすべてのシーケンスを1つのタブに変更するには、sedを使用します。

sed -e 's/  */\t/g' <input_file >output_file

Sedの実装には、\tがタブを意味するものと理解しているものもあれば、文字どおりのタブ文字が必要なものもあります。

可変数のスペースを使用して列を整列する整列された列を含むファイルがある場合、それを unexpand でタブ区切りの列に変換できます。