範囲を使用したtrの奇妙な動作


10

trを使用するときに奇妙な動作をする特定のサーバーがあります。以下は、稼働中のサーバーの例です。

-bash-3.2$ echo "abcdefghijklmnopqrstuvwxyz1234567890"|tr -d [a-z]
1234567890
-bash-3.2$

それは私には完全に理にかなっています。

ただし、これは「特別な」サーバーからのものです。

[root@host~]# echo "abcdefghijklmnopqrstuvwxyz1234567890"|tr -d [a-z]
abcdefghijklmnpqrstuvwxyz1234567890

ご覧のように、すべての小文字の削除は失敗します。しかし、それは文字「o」を削除しました

興味深いのは、次の2つの例ですが、これらはまったく意味がありません。

[root@host~]# echo "abcdefghijklmnopqrstuvwxyz1234567890"|tr -d [a-n]
opqrstuvwxyz1234567890
[root@host~]# echo "abcdefghijklmnopqrstuvwxyz1234567890"|tr -d [a-o]
abcdefghijklmnpqrstuvwxyz1234567890
[root@host~]#

(ここでも、最後の例では「o」が削除されています)

ここで何が起こっているのか誰か誰か知っていますか?私が使用している他のLinuxボックスでは再現できません。


5
接線方向に関連:tr範囲は、を囲まずに記述され[...]ます。だからtr -d '[a-z]'殺すでしょうa-z、そしてまた文字[]tr -d a-z文字だけを殺すために使用しa-zます。
桂佐藤

回答:


24

o現在のディレクトリに名前の付いたファイルがあります

foo> ls
foo> echo "abcdefghijklmnopqrstuvwxyz1234567890"|tr -d [a-z]
1234567890
foo> touch o
foo> echo "abcdefghijklmnopqrstuvwxyz1234567890"|tr -d [a-z]
abcdefghijklmnpqrstuvwxyz1234567890

[a-z]一致が見つかった場合、シェルは文字列を展開します。

これは、パス名展開と呼ばれています。 man bash

パス名の拡張
単語の分割後、-fオプションが設定されていない限り、bashは各単語の*、?、および[の文字をスキャンします。...(...)

bashは拡張を実行します。

[...]囲まれた文字のいずれかに一致します。


あなたが例えば使用して、シェルの展開を確認することができます@クリスechotouch o ; echo tr -d [a-z]この与える:tr -d o
pabouk

8

何が起こっている

シェル(bash)は引数を参照します[a-z]。これはワイルドカードパターン(グロブ)であり、すべての小文字に一致します¹。したがって、シェルはこのパターンに一致するファイル名を探します。3つのケースがあります。

  • 現在のディレクトリのファイルには、1つの小文字の名前はありません。次に、シェルはワイルドカードパターンを変更せずに残しtr、引数-dとを確認し[a-z]ます。これがほとんどのマシンで起こります。
  • 現在のディレクトリ内の1つのファイルには、1つの小文字の名前が付けられています。次に、シェルはパターンをこのファイル名に展開しtr、引数-dとファイル名を確認します。これはサーバーで発生し、文字otr削除されたことがわかるため、一致するファイルが呼び出されますo
  • 現在のディレクトリ内の2つ以上のファイルに、1つの小文字の名前が付けられています。次に、シェルはパターンを一致するファイル名のリストに展開し、tr3つ以上の引数-dとファイル名を確認します。trはの後-dに単一の引数を期待するため、文句を言うでしょう。

すべきこと

コマンドの引数に特殊文字がある場合は、それらをエスケープする必要があります。引数を一重引用符で囲みます'…'(これが最も簡単な方法です。他にもあります)。一重引用符内では、一重引用符自体を除いて、すべての文字が自分自身を表します。引数内に単一引用符がある場合は、それを'\''置き換えます。

tr -d '[a-z]'

ただし、これはおそらくあなたが意図したものではないことに注意してください!これはtr小文字と角括弧を削除するように指示します。それはと同等だtr -d ']a-z['tr '[]a-z'小文字を削除するなど、使用

tr -d a-z

への引数trは文字セットです。正規表現またはワイルドカードパターンで文字セットを角かっこで囲んで、文字セットであることを示します。ただしtr、一度に1つのキャラクターで機能します。そのコマンドライン引数は、括弧内に置くものです

文字クラスを示すには括弧が必要です。正規表現では、角かっこ内で角かっこを使用して文字クラスを示します。たとえば、[[:lower:]]*任意の数の小文字に[[:lower:]_]*一致し、任意の数の小文字とアンダースコアに一致します。の引数ではtr、セットを括弧で囲む必要がないためtr -d '[:lower:]'tr -d '[:lower:]_'小文字を削除したり、小文字やアンダースコアを削除したりします。

¹ 一部のロケールでは、他の文字にマッチします


1
Solaris 10(および他の古代SysVベースのUnices)では、を使用する必要tr -d '[a-z]'があることに注意してください/usr/bin/tr。で/usr/xpg4/bin/trtr -d a-z動作しますが、もtr -d '[a-z]'削除され[ません]
ステファンChazelas

1
/usr/xpg4/bin/tr -d '[a-z]'削除ではない[]明らかにSolarisの11で修正されました
ステファンChazelas
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.