LayerX エンジニアブログ

LayerX の エンジニアブログです。

Devin に怒られたので、macOS の BSD grep で \d が使える謎を追うことにした

バクラク事業部 PlatformEngineering 部 SRE グループマネージャー 兼 執行役員 CISO の @kani_b です。

タイトルからは想像しにくい書き出しですが、みなさん Devin はもうお使いでしょうか?LayerX でもエンジニア組織全体で積極的な利用が進んでいます。今回は導入当時に起きたおもしろ話を共有します。

2ヶ月くらい前、バクラク事業部で Devin を使いはじめることとなり、事業部 CTO の @yyoshiki41 が勢いよくレポジトリのセットアップを進めて、ついに Devin からの初 Pull Request が出てきました。

わ、ワイか…と思いつつ、詳細を確認していきました。

修正の内容

修正対象は、 バクラクの各サービスが集約された monorepo である layerone において、環境構築をおこなうシェルスクリプトを修正するものです。どうやら Devin が Workspace として利用する Ubuntu では動かなかったようです。作成された Pull Request に含まれる差分を見てみましょう。

 check-docker-compose-version() {
   # check docker-compose version
-  docker_compose_version=$(docker compose version | grep -o '\d\+\.\d\+.\d\+')
+  docker_compose_version=$(docker compose version | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+')

この行は、セットアップスクリプトにおいて docker-compose のバージョンをチェックするためのもので、私が入社して開発環境をセットアップする際に遭遇した問題を修正するために追加したものでした。開発環境セットアップスクリプトの修正は古代より新入社員あるあるイベントの一つとされていますが (※諸説あります) 、Devin も無事に伝統をこなしているようでなによりです。

この差分を見てもう原因にお気づきの方もいらっしゃるかと思いますが、この行で私が追加している grep の正規表現 (\d) は PCRE において利用可能なのものです。Ubuntu 標準である GNU grep では -P オプションを渡す必要があり、 macOS 標準である BSD grep ではそもそも PCRE がサポートされていません。よって、パターンの修正によってこの問題を解決する場合は、 \d を使わず [0-9] という表現に置き換えるのが最も無難といえると思います。私も「ああ確かに grep だもんな…そりゃ動かないわ、ごめんやで」と思いながら、 Approve ボタンに手をかけました。

しかし、この行を追加したのは私の入社時、つまり1年前です。左右の手にそれぞれ飲み物とゴミを持った状態で、飲み物をゴミ箱に投げるミスを人生で3回くらいはやっている私であっても、全エンジニアが環境構築に使うスクリプトを修正する際の動作確認はきちんとやります。何よりこの行はとっくにマージされて、新しく仲間が入社してくる中でも1年無事に動いていたのです。なぜ今…

man の確認

まずは落ち着いて man を読みます。macOS にデフォルトで搭載されたコマンドのうち、 BSD 由来のものの一部の man は、 FreeBSD のオンライン man ページでも確認することができます。

読んでみると、 DESCRIPTION に以下の一文があります。

grep is used for simple patterns and basic regular expressions (BREs); egrep can handle extended regular expressions (EREs).

記載されている通り、 BSD grep は正規表現の記法として基本正規表現 (BRE) と拡張正規表現 (ERE) をサポートします。オプションがない場合 BSD grep は BRE を使い、ERE は egrep もしくは grep -E などによって使用します。 しかし、 BRE にも ERE にもエスケープシーケンスとしての \d は存在しませんので、やはり私が書いた正規表現は動かないはずです。 なぜ動くんだ… と頭を抱えていたのですが、このドキュメントで “正規表現の詳細” として参照されている re_format (7) に答えがありました。 ENHANCED FEATURES という章に、regcomp() を呼び出す際に REG_ENHANCED というフラグを渡すことで利用可能な正規表現について記載されています。

Shortcuts (available for both enhanced basic and enhanced extended REs)

The following shortcuts can be used to replace more complicated bracket expressions.

\d Matches a digit character. This is equivalent to ':digit:'.

\D Matches a non-digit character. This is equivalent to '[^[:digit:]]'.

(以下略)

な、なるほど〜〜〜、このフラグが有効化されているのであれば、 冒頭の正規表現は問題なく動きそうです。となると、あとはコードを読むのが早いですね。

コードの調査

この記述がある man は、調べたところ macOS のみであり、他の BSD 系 OS の man にはそもそも存在していませんでした。そのため、この実装は macOS 限定の可能性が高そうです。 実は macOS に含まれる OSS 由来のツールはそのソースコードが Apple Open Source にて公開されています。ソースコードは GitHub で公開されているので、検索に便利です。

調べたところ、libc における regex.h に REG_ENHANCED の定義がありました。あとは、 grep でそれが有効化されているかを確認します。 ベーシックなコマンドラインツールは text_cmds として公開されており、この中で該当する箇所を発見しました。

github.com

ifdef に記載された条件により、 REG_ENHANCED が有効化されていることがわかりました。 macOS の grep で \d が動いていたのは、Apple によって macOS に enhanced REs が追加され、それが有効化されていたためでした。解決!

LayerX の開発者端末には基本的に macOS (MacBook) が使われています。また、当該のセットアップスクリプトは CI などにおけるビルド時には利用されません。今回 Devin がはじめて Ubuntu を使う開発者となったことで、この問題に気づくことができました。個人的には、 macOS 以外の OS でも積極的に開発できるような状態をバクラクでも作っていきたいと考えており、改めて端末間の環境差異を意識しておくことは重要だなと思うようになりました (この問題自体は、いわゆる開発基盤を作られている方なら1度は当たったことがあるであろう問題だと思いますが…)。

人生の中でこの問題に悩まされることはかなり少ないとは思いますが、もし何かのタイミングでお役に立つことがあれば嬉しいです。

おわりに

バクラク事業部 Platform Engineering 部では grep に興味があるエンジニアを募集し…ているわけではありませんが、こうした日常で遭遇する出来事を「なんとなく」で済ませず、適切に深掘りして調査する好奇心をお持ちの方と働けることが楽しいなと個人的に思っています。先日ご紹介した「春のLT祭り」もそんな発表に溢れていました。

バクラクの SRE やセキュリティについてお話するカジュアル面談なども用意しておりますので、ご興味が少しでもあればお声がけいただけると大変うれしいです。

SRE グループの職務詳細はこちら。

open.talentio.com

プロダクトセキュリティエンジニアの職務詳細はこちら。

open.talentio.com

カジュアル面談はこちらから!

jobs.layerx.co.jp

それでは!