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ボックスでは再現できません。
現在のディレクトリに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
によれば、これはパス名展開と呼ばれます
パス名展開
Word分割後、-fオプションが設定されていない場合、bashは各Wordで*、?、および[の文字をスキャンします。 ...(...)
bashは拡張を実行します。
[...]囲まれた文字のいずれかに一致します。
シェル(bash)は引数[a-z]
を参照します。これはワイルドカードパターン(a glob )で、すべての小文字に一致します¹。したがって、シェルはこのパターンに一致するファイル名を探します。 3つのケースがあります。
tr
は引数-d
および[a-z]
を参照します。これがほとんどのマシンで起こります。tr
は引数-d
とファイル名を参照します。これはサーバーで発生し、o
が文字tr
を削除したことがわかるため、一致するファイルはo
と呼ばれます。tr
は3つ以上の引数-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:]_'
は小文字とアンダースコアを削除します。