「tr」のように「sed」を使用して文字を翻訳できますか?


14

文字のセットを、次のような別のセットの対応する文字に置き換えたいと思います。

original set: ots
"target" set: u.x

foobartest → fuubar.ex.

このような翻訳/音訳は、trコマンドの専門です:

$ echo 'foobartest' | tr 'ots' 'u.x'
fuubar.ex.

残念ながら、trファイルのインプレース変更はサポートしていませんsed
使用したいsedので、一時ファイルをジャグリングするホイールを再発明する必要はありません。


「sed translate characters」の結果を見つけることができなかったので、この質問に自己回答します。魔法のキーワードは最終的に「音訳」されましたが、この機能をできるだけ簡単に見つけられるようにする価値があると考えました。
n.st

このための回避策を実装しようとするときに留意すべきこと:(tr正しく)置換セットの再帰を無視します:echo 'abc' | tr ab bxbxc。原始的な解決策xxcは、既に翻訳された文字に翻訳を再適用するため、それを実行するかもしれません。
n.st

関連:Unicode文字のtrアナログ?(GNUのsedGNUとは逆にtr、マルチバイト文字を翻字することができる)
ステファンChazelas

別の可能性が必要な場合:perlは翻訳を実行できます。POSIXではなく、かなり一般的です。
dave_thompson_085

回答:


24

sed次のyようなコマンドがありますtr

$ echo 'foobartest' | sed 'y/ots/u.x/'
fuubar.ex.

yコマンドは一部であり、POSIXのsed仕様なので、それだけで任意のプラットフォームについて取り組む必要があります。

そして、sedなので、ファイルを編集済みのバージョンに置き換えて、面倒な一時ファイルのビジネスを回避できます(POSIXで指定されていないオプションの実装がsedサポート-iされている場合):

$ sed -i 'y/ots/u.x/' some-file.txt

@StéphaneChazelasそれを指摘してくれてありがとう。私は今まで内部の仕組みに気づいていませんでした。私はそれを言及するために私の答えを編集しました。
n.st

おかげで、これは非常に便利です!VIM(CentOS 7.3上の8.0.1092)で動作すると期待していましたが、動作しません。sedは何もしないはずですが、VIMはそうしますか?
dotancohen

1
@dotancohen Vimの置換関数がsed'sをモデルにしているからといって、他の関数も同様であることを意味しません。;)Vimメーリングリストには、同等のものを見つけるスレッドありますy/abc/def/。最適なオプションはのよう:%call setline(".", tr(getline("."),"abc","def"))です。
n.st

8

あなたの場合のように、サイズを変更せずに文字を音訳している場合(とにかく、GNUのようないくつかの実装はtrシングルバイト文字のみをサポートします)、次のことができます:

tr 'ots' 'u.x' < file 1<> file

つまりtr、ファイル自体を上書きします。

これはsed -i、いくつかのアカウントよりも優れています。

  • 追加のディスク領域は必要ありません(一部のスパースファイル、コピーオンライトの特殊なケースを除く)
  • iノード番号、所有権、アクセス許可、ACLを保持します...
  • シンボリックリンクでも問題なく動作し、ハードリンクを壊しません
  • 一時ファイルが強制終了されたままになることはありません。

欠点の1つは、中断された場合、ファイルが半翻訳されることになります(ただし、この場合は、もう一度実行して終了できます)。一部のsed実装では、コマンドが成功しない限り、元のファイルが変更されないようにすることで、それを正しく処理します。


3
翻訳セットに再帰がある場合は、翻訳の再実行に注意してくださいecho 'abc' | tr ab bx
n.st

1
@ n.st、はい、それが私がこのケースで言っ理由です、それを綴る価値があることに同意しますが。
ステファンシャゼラス

結局、一時ファイルを操作する必要がありました:gist.github.com/n-st/048facd0c12f105ac122030fb58b962f —マルチバイト文字がGNUの使用を不可能にtrし、symlink-heavy PXE環境でsed -iは、めちゃくちゃ待っていました起こる…:/
n.st

@ n.st、iconv -t cp437その方が適切だと思われます。
ステファンシャゼラス

iconv入力ファイルにcp437でエンコードされたバイトが既に含まれている場合、または複数のエンコードが混在している場合は中断します。そのため、一般的なケースでは望ましいのですが、このケースでは手動で置換する方がより堅牢です。
n.st

4

別の選択肢として、主な問題がファイルのインプレース変更のサポートの欠如である場合spongemoreutilsパッケージのツールに興味があるかもしれません:

tr 'ots' 'u.x' < file | sponge file

に書き込みますが、入力が完了すると書き込みfile専用に開きfileます。マンページから:

sponge標準入力を読み取り、指定されたファイルに書き出します。シェルリダイレクトとは異なり、スポンジは出力ファイルを開く前にすべての入力を吸収します。これにより、同じファイルを読み書きするパイプラインを構築できます。

メモリに保持できない非常に大きなファイルがない限り、sponge動作します。


2
1つの問題は、spongeそれがまだ上書きすることであるfile場合にはtr失敗した(もし書き込みがあったが、へのアクセスを読んでいない場合は、インスタンスのためにfile
ステファンChazelas

ああ、確かにそうです。私はそれを期待していなかった。ありがとう。
mindriot

cat file >; fileコマンドが成功した場合にのみ宛先に名前が変更される一時sed -iファイルに出力を書き込むksh93 の演算子を参照してください(ただし、元のファイルを上書きする代わりに新しいファイルを作成します)。
ステファンシャゼラス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.