Last active
March 18, 2018 04:22
-
-
Save hogashi/d12df8550890beaa769d3223ff12baea to your computer and use it in GitHub Desktop.
whichコマンドの内容理解(シェルスクリプト)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /bin/sh | |
# シェルのオプションの設定 | |
# `-e` : コマンドが0以外のステータスで終了した場合即座に終了(例外あり) | |
# `-f` : パス名のワイルドカード展開を無効 | |
# http://itpro.nikkeibp.co.jp/article/COLUMN/20060227/230881/ | |
set -ef | |
# `$KSH_VERSION` が確認できたらkshなので、それ用の `puts` を定義する | |
# `printf` で引数を表示したあと改行するようにしている | |
# kshでは `print -r` でエスケープを無視してそのまま出力する | |
# kshの `print` はデフォルトで改行する | |
# https://orebibou.com/2014/11/%E7%8F%BE%E5%9C%A8%E4%BD%BF%E3%82%8F%E3%82%8C%E3%81%A6%E3%81%84%E3%82%8Bksh%E3%81%AE%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B3%E7%A2%BA%E8%AA%8D/ | |
# http://www.geocities.jp/taka_owl2005/job/UNIX/tool/ksh.html#print | |
if test -n "$KSH_VERSION"; then | |
puts() { | |
print -r -- "$*" | |
} | |
else | |
puts() { | |
printf '%s\n' "$*" | |
} | |
fi | |
ALLMATCHES=0 | |
# オプションの取得 | |
# `getopts` により `$ which -a TARGET` のときは `$whichopts` に `a` が入り、 | |
# "マッチした全ての候補を表示する"フラグを立てる | |
# それ以外(何もないか、a以外のオプション)のときは `$whichopts` に `?` が入る | |
# `while` で繰り返すと `-abcd` などを全て見ることができる | |
# http://linux.just4fun.biz/?%E9%80%86%E5%BC%95%E3%81%8D%E3%82%B7%E3%82%A7%E3%83%AB%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88/getopts%E3%82%92%E5%88%A9%E7%94%A8%E3%81%97%E3%81%A6%E5%BC%95%E6%95%B0%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B%28bash%E3%83%93%E3%83%AB%E3%83%89%E3%82%A4%E3%83%B3%29 | |
# http://takuya-1st.hatenablog.jp/entry/2015/12/24/234238 | |
while getopts a whichopts | |
do | |
case "$whichopts" in | |
a) ALLMATCHES=1 ;; | |
?) puts "Usage: $0 [-a] args"; exit 2 ;; | |
esac | |
done | |
# `$OPTIND` は `getopts` でセットされる変数で、 | |
# プログラム名からオプションまでの個数が入る(よって最低でも1) | |
# オプションより後ろの引数は数えられていない | |
# 一方 `$*` にはプログラム名を含まない引数のみ入っているので、 | |
# `-1` することでオプションだけシフトできるよう数を合わせている | |
# つまり引数リストからオプションを取り除き、 | |
# 検索対象だけにする | |
# http://shellscript.sunone.me/parameter.html | |
shift $(($OPTIND - 1)) | |
# `$#` は引数( `$*` )の数がセットされた変数 | |
# 残っている引数が0個、つまり検索対象が指定されていないとき、 | |
# このプログラムが返す終了ステータスを1にセットする | |
# http://shellscript.sunone.me/variable.html#%E7%89%B9%E6%AE%8A%E5%A4%89%E6%95%B0%E4%B8%80%E8%A6%A7%E8%A1%A8 | |
if [ "$#" -eq 0 ]; then | |
ALLRET=1 | |
else | |
ALLRET=0 | |
fi | |
# 環境変数 `$PATH` の末尾に `:` がついている場合、 | |
# システム全体の検索パスがその後ろに追加される | |
# `::` と2つつけたときはその2コロン間にシステム全体の検索パスが追加される | |
# ここでは末尾に `:` があった場合に `::` にしている | |
# 意図が不明…… | |
# https://qiita.com/mollifier/items/2dc274244ac698bb943b | |
case $PATH in | |
(*[!:]:) PATH="$PATH:" ;; | |
esac | |
# `$@` は配列化された引数リスト | |
# つまり、指定された引数それぞれについて | |
# 引数がないときは何もせずに抜ける | |
for PROGRAM in "$@"; do | |
# 以下の処理が終わるまでに0に書き換えられなかったら失敗 | |
RET=1 | |
# Internal Field Separator `$IFS` の中身の退避 | |
# `$IFS` は単語の区切りとなる文字がセットされている環境変数 | |
# https://qiita.com/kawaz/items/00a4b1693bf4cf67e8ca | |
IFS_SAVE="$IFS" | |
# `$IFS` を `:` に設定 | |
# 後述の `$PATH` の走査のため | |
IFS=: | |
# 指定に `/` が含まれていて、それが通常ファイルかつ実行可能なら | |
# それをそのまま出力するだけ | |
# それ以外なら | |
# `$PATH` に何も入っていないとき、パスとして `$ELEMENT` にはカレントを入れておく | |
# `$PATH` のある場所に指定のファイルが通常ファイルかつ実行可能で存在したら表示 | |
# "マッチした全ての候補を表示する"フラグが立っていなかったら、 | |
# 1つ見つけた時点で即座に `for` ループを出る | |
# いずれでも1つでも見つかったら `$RET` を0にして成功を示しておく | |
# 走査が終了したら `$IFS` を元に戻す | |
# 失敗( `$RET` が0でない)ならこのプログラムが返す終了ステータスを1にセットする | |
case $PROGRAM in | |
*/*) | |
if [ -f "$PROGRAM" ] && [ -x "$PROGRAM" ]; then | |
puts "$PROGRAM" | |
RET=0 | |
fi | |
;; | |
*) | |
for ELEMENT in $PATH; do | |
if [ -z "$ELEMENT" ]; then | |
ELEMENT=. | |
fi | |
if [ -f "$ELEMENT/$PROGRAM" ] && [ -x "$ELEMENT/$PROGRAM" ]; then | |
puts "$ELEMENT/$PROGRAM" | |
RET=0 | |
[ "$ALLMATCHES" -eq 1 ] || break | |
fi | |
done | |
;; | |
esac | |
IFS="$IFS_SAVE" | |
if [ "$RET" -ne 0 ]; then | |
ALLRET=1 | |
fi | |
done | |
# 上までで指定した、このプログラムが返す終了ステータスで、終了する | |
exit "$ALLRET" | |
# Environment | |
# $ uname -a | |
# Linux **** 4.4.0-104-generic #127-Ubuntu SMP Mon Dec 11 12:16:42 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux | |
# $ cat /etc/os-release | |
# NAME="Ubuntu" | |
# VERSION="16.04.3 LTS (Xenial Xerus)" | |
# ID=ubuntu | |
# ID_LIKE=debian | |
# PRETTY_NAME="Ubuntu 16.04.3 LTS" | |
# VERSION_ID="16.04" | |
# HOME_URL="http://www.ubuntu.com/" | |
# SUPPORT_URL="http://help.ubuntu.com/" | |
# BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/" | |
# VERSION_CODENAME=xenial | |
# UBUNTU_CODENAME=xenial | |
# References | |
# http://itpro.nikkeibp.co.jp/article/COLUMN/20060227/230881/ | |
# https://orebibou.com/2014/11/%E7%8F%BE%E5%9C%A8%E4%BD%BF%E3%82%8F%E3%82%8C%E3%81%A6%E3%81%84%E3%82%8Bksh%E3%81%AE%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B3%E7%A2%BA%E8%AA%8D/ | |
# http://linux.just4fun.biz/?%E9%80%86%E5%BC%95%E3%81%8D%E3%82%B7%E3%82%A7%E3%83%AB%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88/getopts%E3%82%92%E5%88%A9%E7%94%A8%E3%81%97%E3%81%A6%E5%BC%95%E6%95%B0%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B%28bash%E3%83%93%E3%83%AB%E3%83%89%E3%82%A4%E3%83%B3%29 | |
# http://takuya-1st.hatenablog.jp/entry/2015/12/24/234238 | |
# http://shellscript.sunone.me/parameter.html | |
# http://shellscript.sunone.me/variable.html#%E7%89%B9%E6%AE%8A%E5%A4%89%E6%95%B0%E4%B8%80%E8%A6%A7%E8%A1%A8 | |
# https://qiita.com/mollifier/items/2dc274244ac698bb943b | |
# https://qiita.com/kawaz/items/00a4b1693bf4cf67e8ca |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment