バッシュグロビングの歴史


11

Bashの「グロビング」と正規表現が同一でない歴史的な理由はありますか?たとえば、Bash [1-2]*では1または2で始まり、その後に何かが続くものに一致すると思いますが、正規表現[1-2]*は1と2のシーケンスのみに一致します。私のBashスクリプトとREGEX fooはどちらも非常に弱く、私はこれらの違いに関連する問題に定期的に遭遇しました。


3
rm -- ^[^.].*\.txt$代わりに行うことを検討しrm -- *.txtますか?
ステファンChazelas


ファイル名を操作して正規表現を取るコマンドがあります。たとえば、ファイル名の検索、検索、find . -regex ".*\.txt$" | xargs rm --またはファイル名のrename変更の場合sed、一部のシステムではが異なることに注意してくださいrename
ctrl-alt-delor 2014年

@richard、私^[^.].*\.txt$はドットファイルを無視することを考慮に入れるべきでした。これ-regexはGNU拡張機能であることに注意してください。ksh93やzshなどの一部のシェルは、正規表現をグロブに組み込むことができます(例:ksh93 -c 'echo ~(E:^[^.].*\.txt$)'
StéphaneChazelas

2
そのbashは、既存の慣例に非常に注意深く従い、矛盾する変更と拡張を両立できないようにすることは、その最大の強みの1つです。
ormaaj 14年

回答:


12

bash80年代後半に最初に設計されたのkshは、csh / tcshのインタラクティブ機能を備えたの部分的なクローンです。

グロビングの起源は、それが構築する初期のシェルに見られる必要があります。

kshそれ自体はBourneシェルの拡張です。Bourneシェル自体(1979年にUnix V7で最初にリリースされた)は最初からクリーンな実装でしたが、Thompsonシェル(V1のシェル-> V6)から完全に逸脱したわけではなく、Masheyシェルの機能が組み込まれていました。

特に、コマンド引数はまだ空白で区切られており、|現在は新しいパイプ演算子ですが^、代替としてサポートされています(また、そう[!a-z]しない理由も説明しています[^a-z]$1は、スクリプトの最初の引数であり、バックスラッシュは依然としてエスケープ文字でした。そのため、正規表現演算子(^\|$)の多くは、シェルで独自の特別な意味を持っています。

Thompsonシェルは、グロビングのために外部ユーティリティに依存していました。sh引用符で囲まれていない*[または?sがコマンドで見つかった場合、コマンドはからまで実行されglobます。

rm *.txt

グロブを実行することになります:

["glob", "rm", "*.txt"]

そしてglobはrm、そのパターンに一致するファイルのリストで実行されることになります。

grep a.\*b *.txt

次のように実行さglobれます:

["glob", "grep", "a.\252b", "*.txt"]

*上記の防止、その性質上、8番目のビットを設定することにより引用されているglobワイルドカードとして扱うから。glob次に、を呼び出す前にそのビットを削除しますgrep

正規表現で同等のことを行うには、次のようになります。

regexp rm '\.txt$'

または:

regexp rm '^[^.].*\.txt$'

ドットファイルを除外します。

演算子がシェルの特殊文字を兼ねているため、演算子をエスケープする必要があるため、.ファイル名に共通する正規表現演算子は、ファイル名を一致させるのにあまり適しておらず、初心者には複雑です。ほとんどの場合、必要なのは、1つ()または任意の数()の文字を置き換えることができるワイルドカードだけです。?*

現在、異なるシェルは異なるグロビング演算子を追加しました。現在、kshとzshグロブ(およびbash -O extglobkshグロブのサブセットを実装するある程度)は、ファイル名と現在のシェル構文で使用するのに煩わしくない構文を持つregexpと機能的に同等です。たとえば、zsh(extendedglob拡張を使用して)では、次のことができます。

echo a#.txt

a後に続くで構成されるファイル名に一致する可能性がある場合(そうではない).txt。より簡単ですecho (^a*\.txt$)(ここでは、シェルがそれを処理する1つの方法であったシェルオペレーターから正規表現演算子を分離する方法として中かっこを使用しています)。

echo (foo|bar|<1-20>).(#i)mpg

ベース名がfoo、bar、または1から20までの10進数であるmpgファイル(大文字と小文字は区別されません)の場合...

ksh93正規表現(基本、拡張、perlライク、または「拡張」)をグロブに組み込むこともできるようになり(かなりバグが多い)、グロブと正規表現(printf %Rprintf %P)間の変換ツールも提供されます。

echo ~(Ei:.*\.txt)

持つファイルTXT(非隠された)と一致するようにE小文字は区別、正規表現をXtendedでは、私は nsensitively。


クールな書き込み!~(opt:pat)大文字のオプションには実際には使用できません。多分print -r -- ~(Ei).*\.txt$。パターンを内側に配置することは、パターンの一部に対してオプションをオンまたはオフに切り替える必要を回避するためにのみ役立つようです。奇妙なことに、同じglob内で複数のパターン言語を組み合わせることもできます。~(Ki)*.~(E)txt$同等です。(最終的に、すべてが正規表現に変換され、内部でlibastの正規表現エンジンに渡されます)。
ormaaj 14年

@ ormaaj、~(Ei:.*\.txt)ksh93 o +などの15年前のバージョンでも動作します。
ステファンChazelas

保存したテストバイナリの1つでも動作します(2014-12-24)が、問題が発生したことを覚えています。kshがまだ商業的に開発されていたとき、物事は常にランダムに壊れ、各バージョン間で再び修正されました。パターンマッチングコードは壊れやすい領域の1つであることを覚えています。
ormaaj

@ormaaj、間に別のもの~(E)x~(E:x)後者がされていることであるアンカー(上のマッチx含むもので、前者の試合だけxあなたがに走った問題のようなものでもよい)、(使用~(-lr)~(E:x)アンカーを削除するには、~(E-lr:x)しないだろう)。いずれにせよ、私はそれが最新バージョンでさえ、かなりバグがあることに同意します。
ステファンChazelas

9

正規の言語は1956年にクリーネによって導入されました。精巧な論文には正規表現の完全な現代表記はありませんでしたが、A*「任意の数の繰り返し」を意味する「クリーンスター」を導入しましたA。次の10年間で、特に.任意の文字について、および?前の文字がオプションであることを意味する、多少の標準表記が登場しました。

Bashのグロビング表記は、1971年にUnix v1にずっと導入されたglobコマンドに由来しています。当時、グロビングは別のプログラムによって実行されていました。後でシェルに移動されました。初期のコマンドは、「任意の1文字」および「任意の文字シーケンス」を意味する必要があります。キャラクターが選ばれた理由はわかりません。はかなり直感的で、正規表現の1つからインスピレーションを得た可能性があります。glob?*?*

Globbingは正規表現ほど一般的であるようには意図されておらず、正規表現は当時あまり普及していなかったため、概念を統一する必要はありませんでした。当初から、ファイル名のパターンと正規表現では構文上の非互換性があり?.とは*意味が異なりました。

bashなどの最新のシェルはglobパターンを拡張しますが、下位互換性を維持しながら段階的に進化しました。ksh88では(1988年バージョンのKornシェルは)通常の正規表現と同じ構文であることができなかったシェルパターンのための拡張構文を導入しましたが、強く触発されました:*(PATTERN)の繰り返しの任意の数を意味するようにPATTERN@(PATTERN1|PATTERN2)意味する「PATTERN1またはPATTERN2、」等

最新バージョンのbash(2.02以降)は、shopt -s extglob最初に発行した場合、ksh88の拡張パターンをサポートします。


Bashはextglobsをサポートしていませんか?私の知る限り、Bash、zsh、および{pd、m} kshは、初期からksh88マニュアルに記載されているものとまったく同じグロブをサポートしています。今日までのKshには、「拡張された」グロブ数量詞を無効にするオプションさえありません。ksh93は、ksh88が持っていたものを超える拡張を行う唯一の束です。
ormaaj 14年

2
@ormaaj Ksh88拡張グロブとextglobオプションは、1998年頃のどこかでbash 2.02に導入されました。Zsh ksh_globは、同じ時期のどこかで3.1シリーズで取得しました。Zshには、独自の多くのグロビング拡張機能がありextended_globます(一部はオプションが必要です)。
Gilles「SO-邪悪なことをやめなさい」2014

そうですか。したがって、実際にはオプションの必要性を正当化するのに十分遅れていました。(私は、デフォルトがオフであることは最近無意味であると思いますが、興味深いです。)
ormaaj

1
@ormaaj、に注意してください、とbashは対照的にksh、extglobは変数で無効にされていないため、bashを非POSIX準拠にします。でkshvar='@(*)'; echo $varで開始することを現在のディレクトリにあるすべてのファイル名に展開@(し、最終的に)にしながら、POSIX必要に応じbash -O extglobて、すべてのファイルに展開されます。(それでも、ここではbashの動作がより意味があると考えるかもしれません(そして、kshの動作は、変数にパターンを持たせたい場合には非常に苦痛です))。そのグロブ構文はそのため非常に扱いにくいです(POSIX / Bourne互換性)。zsh拡張グロブと比較してください。
ステファンChazelas

@StéphaneChazelasそれはすべて本当です、そして私はkshがそれについていくぶん賢いのが好きです。実際にPOSIXに制限されていない限り、プレイすることはめったにありません。IFSを空にする必要があるため、ワードスプリットのほとんどすべての使用法がより優れた機能で置き換えられ、変数にパターンを保存することはとにかく非常に厄介です。bash以外のすべての場所でブレース展開を無効にします。保存されたパターンで完全に安全であることはまだ不可能だと思います。たとえば、この古い脱出の問題は、実際には解決されていません。
ormaaj 14年

1

歴史的理由:はい。リファレンス:http :
//en.wikipedia.org/wiki/Glob_(programming)#Origin

相違点を紹介するためだけに、ここに良い簡単な例を示します。 a*

  • シェルaグロビング:意味は、最初の文字はそれから何でも(a、ab、abca ...)
  • regex:意味は、文字a(a、aa、aaa ...)のゼロ回以上の繰り返し

この意味の不一致は、新規ユーザーにとって非常に混乱するものであることに、私はすぐに同意します。

グロビングは、おそらく初心者にとっては理解しやすいでしょうが、あまり強力ではありません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.