trはアポストロフィを置き換えません。

trはアポストロフィを置き換えません。

このファイルのすべてのアポストロフィを次に変換したいと思いますX

Bob's book
Bob’s book
Bob′s book  # (Might look the same but actually different)

最初のアポストロフィは期待どおりに置き換えられます。

$ cat file | tr "'" "X"
BobXs book
Bob’s book
Bob′s book

しかし、他の2種類のアポストロフィを使用すると、奇妙なことが起こります。

$ cat file | tr "’" "X"
Bob's book
BobXXXs book
BobXX�s book

$ cat file | tr "′" "X"
Bob's book
BobXX�s book
BobXXXs book

どのように機能させるのですか?

答え1

trバイト単位で動作します。つまり、UTF-8などのマルチバイトエンコーディングでは正しく機能しません。私が知っている唯一の解決策は、trUnicodeをサポートするバージョンを見つけたり、sed文字列置換を実行できる他のツールに切り替えることです。

答え2

私にとって、trはOSがUTF-8コードページを使用するように設定されている限り、ASCIIファイルとUTF-8ファイルの両方をうまく処理します。

ここに私の例#1(Solaris 11)があります:

$ locale
LANG=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_ALL=

ご覧のとおり、オペレーティングシステムはutf-8を使用するように設定されています。 utf-8コードページを使用して、次の2つのファイルを作成しました。

$ cat file
Bob’s Bob′s Bob's

$ cat apos
’′'

その後、次のようにすべてのaposを置き換えると予想される結果が得られました。

$ cat file | tr "$(cat apos)" "xxx"
Bobxs Bobxs Bobxs

私の例#2(Solaris 10)は次のとおりです。

$ locale
LANG=
LC_CTYPE="C"
LC_NUMERIC="C"
LC_TIME="C"
LC_COLLATE="C"
LC_MONETARY="C"
LC_MESSAGES="C"
LC_ALL=

ここでは、オペレーティングシステムがutf-8ではなく単純なASCIIを処理するように構成されているため、trを使用してマルチバイト文字のutf-8ファイルを処理するのに問題がある可能性があります。しかし、解決策があります。長いtrコマンドは入力文字の8進表現を可能にするので、指定された文字のすべてのバイトを8進表現に置き換えることができます。

あなたの場合には、以下があります。

char  hex        octal
’     E2 80 99   \342\200\231
′     E2 80 B2   \342\200\262
'     27         \47

最初と2番目のaposは3バイトで表されます。 3番目は標準ASCII(1バイト)です。

したがって、最初の位置を置き換えるには、次のものを使用できます。

$ cat file | tr "\342\200\231" "\0\0x"
Bobxs Bob▒s Bob's

第二:

$ cat file | tr "\342\200\262" "\0\0x"
Bob▒s Bobxs Bob's

第三:

$ cat file | tr "\47" "x"
Bob’s Bob′s Bobxs

一度にすべてを交換するには、次のものを使用できます。

$ cat file | tr "\342\200\231\262\47" "\0\0xxx"
Bobxs Bobxs Bobxs

もちろん完璧ではありません。これにより、ファイル内のすべてのエントリが \342、\200、\231、\262 バイトに置き換えられるため、これらのバイトを含む他のマルチバイト文字が破損します。ただし、ファイルに他のマルチバイト文字が含まれていない場合は機能します。

関連情報