web-dev-qa-db-ja.com

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

ターミナルで、次のようにいくつかの変数charを定義すると、

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

実際には、charは文字列です。

'\"?!

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

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

そして、私は得るだろうと思った

01234

代わりに、私は得ました

0\123

誰かが私に何が起こったのか説明してくれたら本当にありがたいです。

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

8
Robb U

シェルだけでなく、tr自体もバックスラッシュを特殊なエスケープ文字として解釈します。詳細については、そのマニュアルを参照してください。したがって、バックスラッシュを置き換える場合は、trがリテラル\\(2つのバックスラッシュ)を受け取ることを確認する必要があります。これは、たとえば行われる可能性があります。シェルのchar=...\\\\...によって、シェルがバックスラッシュをどのように処理するかを正しく理解しているので、この部分はさらに説明する必要はありません。

これはここでは不便かもしれませんが、他の多くの状況では便利であり、文字セットまたはNULバイトを検索または置換セットの一部にすることができます(それ以外の場合は不可能です)。例えば。 NULで区切られた文字列を改行で区切られた文字列に変換するには、tr '\0' '\n' < /proc/1234/environのようにするか、文字列を小文字にするにはtr '[:upper:]' '[:lower:]'を使用します。 trにエスケープ文字がない場合、これらは不可能です。

17
egmont

二重引用符(')を使用してneedする必要がない限り、文字列とスクリプトは常に一重引用符(")で囲みます。シェルはそれを解釈します。 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

上記で知っておく必要があるのは、シェルの'で囲まれた文字列内に'を取得するには'\''であり、trでバックスラッシュをエスケープしてtrがわかるようにする必要があることだけです。それを後続の"のエスケープではなくリテラルのバックスラッシュとして扱うため。

5
Ed Morton