判断すること
audit-texlive-tags.sh の grep 呼び出しで、起動失敗を 0 件と区別するかどうか。
訂正: 当初この issue は「macOS で動かない(xargs -r が BSD にない)」として起票しましたが、誤りでした。xargs -r は macOS でも動きます。また PCRE 非対応の環境はスクリプト冒頭のチェックが正しく弾きます。残る論点は 2>/dev/null の 1 点だけなので、そこに絞って書き直しました。
現状の整理
grep の呼び出しが 2 箇所とも標準エラーを捨てています。
# 133 行目
| xargs -0 -r grep -EoHn "${image}:[A-Za-z0-9._-]+" 2>/dev/null \
# 142 行目
git ls-files -z | xargs -0 -r grep -oHnP "$pattern" 2>/dev/null || true
grep の終了コードは 3 種類あります。
| code |
意味 |
扱い |
| 0 |
マッチあり |
正常 |
| 1 |
マッチなし |
正常。監査では「drift なし」 |
| 2 |
エラー(オプション不正、ファイル読めない等) |
異常だが、いまは 1 と同じ扱い |
2 が 1 に化けます。 grep が起動すらできなくても hits が空になり、監査は ok を出します。
実際に踏みました
#172(extra_patterns の追加)の検証中の出来事です。正しいパターンを書いたのに 0 件が返り、パターン側の問題だと思い込んで切り分けに手間取りました。
$ git ls-files | xargs grep -oHnP '<正しいパターン>' 2>/dev/null
(0 件)
$ grep -oHnP '<同じパターン>' Dockerfile CHANGELOG.md
Dockerfile:8:2026e
CHANGELOG.md:6:2026d
CHANGELOG.md:11:2026a
2>/dev/null を外して初めて理由が見えました。
grep: invalid option -- P
原因は環境固有のもの(シェル関数として定義された grep が -P を通す一方、xargs が PATH から解決した /usr/bin/grep は BSD grep で通さない)でしたが、問題はそこではありません。エラーが出ていたのに、それが「一致しています」という結果として返ってきたことです。
なぜ問題か
監査の目的は上げ忘れの検出です。検出器が壊れているときに「異常なし」と答えるのは、最も避けたい失敗の形です。
同じ scripts/ 配下の audit-repo-protection.sh には、まさにこの配慮を書いたコメントがあります。
cd の失敗は握り潰さない。空の結果は「一致している」と区別が付かず、何も見ていない監査が ok を出すことになる
audit-texlive-tags.sh の cd "$repo_dir" || exit 1 にも同じ趣旨のコメントがあります。設計思想としては既に存在していて、grep の呼び出しにだけ及んでいません。
これは macOS 固有の話ではありません。Linux 上でも、権限やファイル名の問題で grep が 2 を返せば同じことが起きます。
選択肢
A. 終了コードを見て 2 を異常として扱う(推奨)
set +e
hits=$(cd "$repo_dir" && git ls-files -z | xargs -0 -r grep -EoHn "..." 2>&1)
rc=$?
set -e
if [ "$rc" -gt 1 ]; then
log " ERROR: ${name} — grep が失敗した: $(printf '%s' "$hits" | head -1)"
errors=$((errors + 1))
continue
fi
既に errors カウンタと ERROR 行の枠組みがある(clone 失敗で使っている)ので、そこに乗せられます。xargs は最後に起動した子プロセスの終了コードを返すため、複数回起動された場合に取りこぼす可能性は残りますが、現状の「常に無視」よりは確実に良くなります。
B. 標準エラーを捨てず、そのまま出す
| xargs -0 -r grep -EoHn "..." \
2>/dev/null を消すだけ。エラーはログに出ますが、終了コードは相変わらず区別されないので、気付けるかどうかは人の目次第です。1 文字の変更で済む代わりに保証は弱くなります。
C. 現状維持
実運用は GitHub Actions で、そこでは PCRE も揃っており、これまで問題は起きていません。
補足
|| true(142 行目)も同じ方向の問題を持ちます。set -eu の下でマッチなし(1)を通すために必要ですが、2 も一緒に通しています。A を採るなら、この || true は終了コードの判定に置き換わります。
判断すること
audit-texlive-tags.shの grep 呼び出しで、起動失敗を 0 件と区別するかどうか。現状の整理
grep の呼び出しが 2 箇所とも標準エラーを捨てています。
grep の終了コードは 3 種類あります。
2 が 1 に化けます。 grep が起動すらできなくても
hitsが空になり、監査はokを出します。実際に踏みました
#172(
extra_patternsの追加)の検証中の出来事です。正しいパターンを書いたのに 0 件が返り、パターン側の問題だと思い込んで切り分けに手間取りました。2>/dev/nullを外して初めて理由が見えました。原因は環境固有のもの(シェル関数として定義された grep が
-Pを通す一方、xargsが PATH から解決した/usr/bin/grepは BSD grep で通さない)でしたが、問題はそこではありません。エラーが出ていたのに、それが「一致しています」という結果として返ってきたことです。なぜ問題か
監査の目的は上げ忘れの検出です。検出器が壊れているときに「異常なし」と答えるのは、最も避けたい失敗の形です。
同じ
scripts/配下のaudit-repo-protection.shには、まさにこの配慮を書いたコメントがあります。audit-texlive-tags.shのcd "$repo_dir" || exit 1にも同じ趣旨のコメントがあります。設計思想としては既に存在していて、grep の呼び出しにだけ及んでいません。これは macOS 固有の話ではありません。Linux 上でも、権限やファイル名の問題で grep が 2 を返せば同じことが起きます。
選択肢
A. 終了コードを見て 2 を異常として扱う(推奨)
既に
errorsカウンタと ERROR 行の枠組みがある(clone 失敗で使っている)ので、そこに乗せられます。xargsは最後に起動した子プロセスの終了コードを返すため、複数回起動された場合に取りこぼす可能性は残りますが、現状の「常に無視」よりは確実に良くなります。B. 標準エラーを捨てず、そのまま出す
2>/dev/nullを消すだけ。エラーはログに出ますが、終了コードは相変わらず区別されないので、気付けるかどうかは人の目次第です。1 文字の変更で済む代わりに保証は弱くなります。C. 現状維持
実運用は GitHub Actions で、そこでは PCRE も揃っており、これまで問題は起きていません。
補足
|| true(142 行目)も同じ方向の問題を持ちます。set -euの下でマッチなし(1)を通すために必要ですが、2 も一緒に通しています。A を採るなら、この|| trueは終了コードの判定に置き換わります。