Bashでprintfという名前が、シェル組み込みと外部コマンドの両方として利用できる。
実行せずに、Bashが認識する候補を解決順にすべて表示する。
同名のエイリアスとシェル関数は定義されていないものとする。
適切なコマンドはどれか。
Bashのtypeは、名前が組み込み、関数、エイリアス、外部ファイルのどれとして解決されるかを調べる。-aを付けると全候補を表示する。
詳細解説
which printfwhichは通常PATH上の実行ファイルを探し、Bash組み込みを含む全候補の確認には適さない。
PATH上の外部printfが見つかっても、Bash組み込みの候補まで表示したとはいえない。どのファイルが見つかるかと、Bash内の候補を含むかを分けて読む。
command -v printfBashが実行に使う1つの解決結果は分かるが、全候補を列挙しない。
この設問ではcommand -v printfはprintfという1つの結果を示す。実際に選ばれる候補を知る用途には適するが、同名の外部ファイルまで並べる要件を満たさない。
whereis printfバイナリやマニュアルの所在を探すコマンドで、Bashの組み込み解決順を示さない。
whereisは関連ファイルの所在を探すための道具で、現在のBashにある組み込みという種類や名前解決を列挙するものではない。
type -a printftypeはBashにおける名前の種類を調べ、-aで同名の全候補を表示する。
-aを付けたtypeで、組み込みとPATH上の同名ファイルの両方を確認できる。検証では比較用の外部ファイルを一つだけ用意し、command -vの1結果と対比する。
実際に確かめる
一時的な検証環境で実行できる例です。
LAB_DIR=$(mktemp -d) || exit 1
printf '#!/bin/sh\nexit 0\n' > "$LAB_DIR/printf"
chmod u+x "$LAB_DIR/printf" || exit 1
(
export LC_ALL=C
PATH="$LAB_DIR"
hash -r
LAB_ALL=$(type -a printf)
builtin printf '%s\n' "${LAB_ALL//"$LAB_DIR"/<LAB_DIR>}"
builtin printf 'first=%s\n' "$(command -v printf)"
)
rm -- "$LAB_DIR/printf"
rmdir -- "$LAB_DIR"参考にした公式資料
期待される結果
printf is a shell builtin
printf is <LAB_DIR>/printf
first=printf理解のポイント
- typeはBash自身の名前解決を調べる
- -aは全候補を表示する
- command -vは実行対象となる1候補を示す
確認時の注意
- 確認環境: Bash 5.2 / GNU coreutils。個人設定を読まない新規Bashでerrexit無効。比較用PATH・LC_ALL・hash・alias/関数は子シェル内だけに限定する。HOMEは変更しない。
- 一時ディレクトリに比較用の外部printfを作り、PATHを子シェル内でその場所だけにする。作った外部ファイルを実行する検証ではなく、名前解決の表示を確認する。
- 実際のtype -a出力の一時パス部分だけを<LAB_DIR>へ置換し、ホスト依存の名前と表示の構造を分ける。LC_ALL=Cとhash -rも子シェル内に限定する。
基礎のおさらい
基本例は組み込みと外部ファイル
この問題ではaliasと同名関数を除外し、組み込みとPATH上の外部printfという2種類に絞って観察する。aliasや同名関数を定義した場合には、その定義も候補へ現れ得る。
全候補と最初の結果
type -aの全候補と、command -vが示す一つの結果は用途が違う。外部ファイルを実行せずに調査できる点も確認する。
所在検索との違い
whichやwhereisでファイルの位置が分かっても、Bashが組み込みとして扱う名前の情報を網羅したとは限らない。