منبع اصلی نوشتار زیر در این لینک قرار دارد

کنترل وجود یک فرمان در مسیر PATH


چگونه می‌توانم تعیین کنم که یک فرمان آیا در جایی از PATH من وجود دارد؟

POSIX فرمان داخلی به نام command تعیین می‌کند، که می‌تواند برای این منظور به کار برود:

# POSIX
if command -v qwerty >/dev/null; then
  echo qwerty exists
else
  echo qwerty does not exist
fi

در BASH، یک زوج دستور داخلی بیشتر نیز وجود دارد که ممکن است به کار بروند: hash و type. این هم مثالی با استفاده از hash:

# Bash
if hash qwerty 2>/dev/null; then
  echo qwerty exists
else
  echo qwerty does not exist
fi

یا، اگر ترجیح می‌دهید type:

# Bash
# .بدون در نظر گرفتن دستورات داخلی و غیره می‌کند PATH الزام به جستجوی ‎type -P‎ دستور
if type -P qwerty >/dev/null; then
  echo qwerty exists
else
  echo qwerty does not exist
fi

پوسته Korn در عوض دارای whence می‌باشد:

# ksh
if whence -p qwerty >/dev/null; then
  echo qwerty exists
else
  echo qwerty does not exist
fi

دستور داخلی command همچنین برای دستورات داخلی پوسته صحیح را باز می‌گرداند(برخلاف ‎type -P‎). اگر شما باید به طور مطلق فقط PATH را بررسی کنید، تنها روش POSIX انجام تکرار روی آن است:

# POSIX
IsInPath ()
(
  [ $# -eq 1 ] && [ "$1" ] || return 2
  set -f; IFS=:
  for dir in $PATH; do
    [ -z "$dir" ] && dir=.       # رفتار موروثی
    [ -x "$dir/$1" ] && return
  done
  return 1
)

if IsInPath qwerty; then
  echo qwerty exists
else
  echo qwerty does not exist
fi

توجه نمایید که تابع تعریف شده فوق به جای ابروهای معمول، از پرانتزها در اطراف بدنه استفاده می‌کند. این باعث می‌شود بدنه در یک پوسته فرعی اجرا گردد، و این به دلیل آنست که ما می‌خواهیم نیازی به خنثی نمودن ‎set -f‎ یا IFS نداشته باشیم.

رویکرد تکرار کننده در اسکریپت‌های configure نیز استفاده می‌شود. این هم نگارش ساده شده‌ای از یک چنین تستی:

# Bourne
save_IFS=$IFS
IFS=:
found=no
for dir in $PATH; do
  if test -x "$dir/qwerty"; then
    echo "qwerty is installed (in $dir)"
    found=yes
    break
  fi
done
IFS=$save_IFS
if test $found = no; then
  echo "qwerty is not installed"
fi

اسکریپت‌های واقعی configure معمولاً خیلی بیشتر از این پیچیده هستند، چون آنان ممکن است با سیستم‌هایی سر و کار داشته باشند که در آنها ‎$PATH‎ به وسیله کاراکترهای کولن جدا نمی‌شوند، یا سیستم‌هایی که در آنها شاید برنامه‌های اجرایی پسوندهای انتخابی مانند ‎.EXE‎ دارند، یا متغیرهای ‎$PATH‎ که دایرکتوری کاری جاری به عنوان یک رشته تهی در آنها گنجانده شده‌اند و غیره. اگر به چنین مطالبی علاقمند هستید، پیشنهاد می‌کنم یک اسکریپت ‎configure‎ واقعی تولید شده با autoconf گنو را بخوانید. آنها بیش از آن بلند و پیچیده می‌باشند که در این پرسش و پاسخ قرار داده شوند.

فرمان which (که غالباً یک اسکریپت csh است، اگر چه گاهی نیز به صورت باینری کامپایل شده است) برای این منظور قابل اطمینان نیست. which نمی‌تواند یک کد خروج سودمند تنظیم کند، و حتی نمی‌تواند خطاها را در stderr بنویسد. بنابر این، برای مطلع شدن از اجرای موفقیت آمیز آن، باید خروجی‌اش تفکیک بشود(هر جا که خروجی نوشته بشود).

# Bourne.  Last resort -- using which(1)
tmpval=`LC_ALL=C which qwerty 2>&1`
if test $? -ne 0; then
  # این ماشین یک کد خروج غیرصفر ‎which(1)‎ در حال حاضر فرض خواهیم نمود که اگر ‎
  # تنظیم کند، به راستی ناموفق  بوده. هنوز باید حالتی را ببینیم که در آن‎
  #  درست  مثل موفقیت غلط -- یک عدم موفقیت غلط تنظیم می‌کند which(1)‎
  echo "qwerty is not installed.  Please install it."

else
    #  صفر را بازگردانده، که به معنی موفقیت آن نیست. جستجو برای رشته های خطا
    case "$tmpval" in
      *no\ *\ in\ *|*not\ found*|'')
        echo "qwerty is not installed.  Please install it."
        ;;
      *)
        echo "Congratulations -- it seems you have qwerty (in $tmpval)."
        ;;
    esac
fi

توجه نمایید که خروجی ‎which(1)‎ موقعی که دستوری را پیدا نمی‌کند در تمام سکوها یکسان نیست. برای مثال، در ‎HP-UX 10.20‎، این پیغام خطا را چاپ می‌کند ‎no qwerty in /path /path /path ...‎، در ‎OpenBSD 4.1‎، این پیغام خطا را ‎qwerty: Command not found.‎، در دبیان (حداقل ‎3.1‎ تا ‎5.0‎) و SuSE، ابداً چیزی چاپ نمی‌کند، در ‎Red Hat 5.2‎، چاپ می‌کند ‎which: no qwerty in (/path:/path:...)‎، در ‎Red Hat 6.2‎، همان پیغام را می‌نویسد، اما به جای خروجی استاندارد در خطای استاندارد، و در Gentoo، چیزی در stderr می‌نویسد.

ما قویاً پیشنهاد می‌کنیم از which استفاده نکنید. به جای آن یکی از دستورات داخلی یا رویکردهای تکرار را به کار ببرید.


پرسش و پاسخ 81 (آخرین ویرایش ‎2012-03-14 11:57:13‎ توسط pgas)