tr "\'\\\"\?\!" "01234"コマンドが機能しないのはなぜですか?

tr "\'\\\"\?\!" "01234"コマンドが機能しないのはなぜですか?

端末で次のようにいくつかの変数charを定義した場合:

export char=\'\\\"\?\!

実際、charは文字列です。

'\"?!

次に、数値に置き換えるtrコマンドを使用します。'\"?!01234

tr "\'\\\"\?\!" "01234"

手に入れると思った

01234

代わりに私は得る

0\123

誰かが私に何が起こっているのかを説明することができればとても感謝します。

sed各文字を個別にコマンドに置き換えることでこの問題を回避できるようですが、なぜですか?

答え1

シェルだけでなく、独自のtrバックスラッシュを特殊なエスケープ文字として解釈します。詳細については、該当するマニュアルを参照してください。したがって、バックスラッシュを変更するには、trリテラル(バックスラッシュ2つ)を受け取ったことを確認する必要があります。\\たとえば、これはシェルで行うことができ、char=...\\\\...シェルでバックスラッシュを処理する方法を正しく理解しているため、このセクションでは追加の説明は必要ありません。

これはユーザーにとっては不便かもしれませんが、他の多くの場合に便利で、文字セットまたはNULバイトを検索または代替セットの一部として許可します(そうでなければ不可能です)。たとえば、NULで区切られた文字列を改行区切りの文字列に変換するには、同様の操作を実行するか、tr '\0' '\n' < /proc/1234/environ小文字の文字列を使用できますtr '[:upper:]' '[:lower:]'trエスケープ文字がなければ、どちらも不可能です。

答え2

文字列とスクリプトを常に一重引用符(')で囲みます。必要"シェルにそれを解釈させるには、二重引用符()を使用します。バラよりhttps://mywiki.wooledge.org/Quotes。二重引用符を使用すると、シェルを招待して「エスケープ」地獄に陥ります。文字列の文字をエスケープして、シェルが最初にその文字をすべて使用してから、ツールが使用できるように再エスケープする必要があります。 1つのレイヤーの代わりに複数のエスケープレイヤーを追加する必要があります。これを行わないで、代わりに一重引用符を使用してください。

$ printf '%s\n' ''\''\"?!'
'\"?!

$ printf '%s\n' ''\''\"?!' | tr ''\''\\"?!' '01234'
01234

変数を定義するときも同様ですchar。すべてのバックスラッシュを使用する代わりに:

export char=\'\\\"\?\!

文字列を正しく一重引用符で囲みます。

$ export char=''\''\"?!'

$ printf '%s\n' "$char"
'\"?!

$ printf '%s\n' "$char" | tr ''\''\\"?!' '01234'
01234

上記で知っておくべきことは、'シェルからa - に含まれる文字列を取得するには、バックスラッシュをエスケープしなければ文字通りのバックスラッシュとして処理し、後続のエスケープではないことを知ることができるということです。''\''trtr"

関連情報