bash - কিভাবে একটি প্রোগ্রাম একটি বাশ স্ক্রিপ্ট থেকে বিদ্যমান চেক কিভাবে?
(20)
আমি কিভাবে একটি প্রোগ্রাম বিদ্যমান যে একটি উপায় বিদ্যমান, যে একটি ত্রুটি ফেরত বা প্রস্থান ফিরে, বা স্ক্রিপ্ট সঙ্গে অবিরত হবে?
এটা সহজ হওয়া উচিত মনে হচ্ছে, কিন্তু এটি আমাকে stumping করা হয়েছে।
উত্তর
POSIX সামঞ্জস্যপূর্ণ:
command -v <the_command>
bash
নির্দিষ্ট পরিবেশের জন্য:
hash <the_command> # For regular commands. Or...
type <the_command> # To check built-ins and keywords
ব্যাখ্যা
which
এড়িয়ে চলুন। খুব কম কাজ করার জন্য আপনি এটি চালু করছেন এমন বাহ্যিক প্রক্রিয়াটি নয় (মানে hash
, type
বা command
সস্তা উপায়), আপনি প্রকৃতপক্ষে যা চান তা করতে বিল্টিনগুলিতেও নির্ভর করতে পারেন, বাইরের কমান্ডগুলির প্রভাবগুলি সিস্টেম থেকে সিস্টেম থেকে সহজেই পরিবর্তিত।
কেন যত্ন?
- অনেক অপারেটিং সিস্টেমে এমন একটিও রয়েছে
which
কোনও প্রস্থান স্থিতি সেট করে না , অর্থাত্if which foo
সেখানে কাজ না করে এবং সর্বদাfoo
উপস্থিত থাকে তাও জানায়, এমনকি এটি না থাকলেও (এটি মনে রাখবেন যে কিছু POSIX শেল প্রদর্শিত হয় এইhash
জন্য খুব)। - অনেক অপারেটিং সিস্টেম কাস্টম এবং খারাপ স্টাফ মত আউটপুট পরিবর্তন বা এমনকি প্যাকেজ ম্যানেজার মধ্যে হুক করতে না।
সুতরাং, which
ব্যবহার করবেন না। পরিবর্তে এর মধ্যে একটি ব্যবহার করুন:
$ command -v foo >/dev/null 2>&1 || { echo >&2 "I require foo but it's not installed. Aborting."; exit 1; }
$ type foo >/dev/null 2>&1 || { echo >&2 "I require foo but it's not installed. Aborting."; exit 1; }
$ hash foo 2>/dev/null || { echo >&2 "I require foo but it's not installed. Aborting."; exit 1; }
(ক্ষুদ্র পার্শ্ব-নোট: কিছু সুপারিশ করবে 2>&-
একই 2>/dev/null
কিন্তু short - এটি অসত্য । 2>&-
FD2 বন্ধ করে দেয় যা স্টেডারে লেখার সময় প্রোগ্রামে একটি ত্রুটি সৃষ্টি করে। , যা সাফল্যের সাথে লেখা থেকে এবং আউটপুট (এবং বিপজ্জনক!) বাদ দিয়ে খুব ভিন্ন।
আপনার হ্যাশ ব্যাং যদি /bin/sh
তবে আপনার পিসিক্স কী বলে সে বিষয়ে যত্ন নেওয়া উচিত। type
এবং hash
প্রস্থান কোডগুলি POSIX দ্বারা খুব ভালভাবে সংজ্ঞায়িত করা হয় না এবং কমান্ডটি বিদ্যমান না থাকলে hash
সফলভাবে প্রস্থান করতে দেখা যায় (এখনও type
সাথে এটি দেখা যায় না)। command
প্রস্থান অবস্থাটি POSIX দ্বারা ভালভাবে সংজ্ঞায়িত করা হয়েছে, যাতে এটি সম্ভবত এটি ব্যবহার করা সবচেয়ে নিরাপদ।
যদিও আপনার স্ক্রিপ্ট bash
ব্যবহার করে তবে POSIX নিয়মগুলি এখন আর কোনও ব্যাপার নয় এবং উভয় type
এবং hash
ব্যবহার করার জন্য পুরোপুরি নিরাপদ হয়ে উঠেছে। এখন type
করুন PATH
অনুসন্ধানের জন্য PATH
এবং hash
পার্শ্ব প্রতিক্রিয়া আছে যে কমান্ডের অবস্থান hash
করা হবে (পরবর্তী সময় আপনি দ্রুত এটি ব্যবহার করবেন), যা সাধারণত এটি একটি ভাল জিনিস যা আপনি সম্ভবত তার অস্তিত্বের জন্য পরীক্ষা করে দেখেন আসলে এটি ব্যবহার করার জন্য আদেশ।
একটি সাধারণ উদাহরণ হিসাবে, এখানে একটি ফাংশন রয়েছে যা gdate
চালায় যদি এটি বিদ্যমান থাকে, অন্যথায় date
:
gnudate() {
if hash gdate 2>/dev/null; then
gdate "[email protected]"
else
date "[email protected]"
fi
}
@ লুনাথ এবং @ গ্রেগভ এর উত্তরগুলি সম্প্রসারিত করে, এখানে এমন কোডের জন্য কোড রয়েছে যা সহজেই if
বিবৃতির মধ্যে চেকটি রাখতে চান:
exists()
{
command -v "$1" >/dev/null 2>&1
}
এটি কিভাবে ব্যবহার করবেন তা এখানে:
if exists bash; then
echo 'Bash exists!'
else
echo 'Your system does not have Bash'
fi
আপনি যদি প্রোগ্রামের অস্তিত্বের জন্য পরীক্ষা করে থাকেন, তবে সম্ভবত আপনি এটি পরেও চালাতে যাচ্ছেন। কেন প্রথম স্থানে এটি চালানোর চেষ্টা করবেন না?
if foo --version >/dev/null 2>&1; then
echo Found
else
echo Not found
fi
এটি কেবল একটি PATH ডিরেক্টরি এবং ফাইল অনুমতিগুলি দেখার চেয়ে প্রোগ্রামটি আরও বেশি বিশ্বাসযোগ্য পরীক্ষা।
প্লাস আপনি আপনার প্রোগ্রাম, যেমন তার সংস্করণ থেকে কিছু দরকারী ফলাফল পেতে পারেন।
অবশ্যই ত্রুটিগুলি হল যে কিছু প্রোগ্রাম শুরু করতে ভারী হতে পারে এবং --version
অবিলম্বে (এবং সফলভাবে) প্রস্থান করার জন্য --version
বিকল্প বিকল্প নেই।
আমাদের সিআই সার্ভার স্থাপনের অংশ হিসাবে git
ইনস্টল করা হয়েছে কিনা তা যাচাই git
হয়েছিল। নিম্নরূপ আমার চূড়ান্ত ব্যাশ স্ক্রিপ্ট ছিল (উবুন্টু সার্ভার):
if ! builtin type -p git &>/dev/null; then
sudo apt-get -y install git-core
fi
এই অন্য কেউ সাহায্য আশা করি!
আমি আমার .bashrc এ সংজ্ঞায়িত একটি ফাংশন আছে যা এই সহজ করে তোলে।
command_exists () {
type "$1" &> /dev/null ;
}
এখানে এটি কীভাবে ব্যবহৃত হয় তার একটি উদাহরণ (আমার .bash_profile
থেকে।)
if command_exists mvim ; then
export VISUAL="mvim --nofork"
fi
আমি এটি ব্যবহার করি কারণ এটি খুব সহজ:
if [ `LANG=C type example 2>/dev/null|wc -l` = 1 ];then echo exists;else echo "not exists";fi
অথবা
if [ `LANG=C type example 2>/dev/null|wc -l` = 1 ];then
echo exists
else echo "not exists"
fi
এটি শেল বিল্টিন এবং প্রোগ্রাম ইকো স্ট্যাটাস স্টেডাউট ব্যবহার করে এবং কোন কমান্ড পাওয়া যায় না যদি অন্যদিকে stderr এর জন্য কিছুই ব্যবহার না করে, এটি শুধুমাত্র stderr এ echos স্থিতি।
আমি বলতে চাই যে কোন পোর্টেবল এবং 100% নির্ভরযোগ্য উপায় উদীয়মান alias
es হয়। উদাহরণ স্বরূপ:
alias john='ls --color'
alias paul='george -F'
alias george='ls -h'
alias ringo=/
অবশ্যই শুধুমাত্র শেষটি সমস্যাযুক্ত (রিংগোতে কোনও অপরাধ নেই!) তবে তাদের সবই বৈধ alias
এস- command -v
এর দৃষ্টিকোণ থেকে এসেছে।
ringo
মত ringo
ব্যক্তিদের প্রত্যাখ্যান করার জন্য, আমাদের নির্মিত শেলের আউটপুট আউটপুটটি আউটপুট করতে হবে এবং তাদের মধ্যে পুনরায় লিখতে হবে ( command -v
এখানে command -v
চেয়ে বড় নয়।) এর জন্য কোনও পোর্টেবল সমাধান নেই, এমনকি একটি ব্যাশও - নির্দিষ্ট সমাধান বরং ক্লান্তিকর।
উল্লেখ্য যে এইরকম সমাধানটি নিঃশর্তভাবে alias ls='ls -F'
প্রত্যাখ্যান করবে
test() { command -v $1 | grep -qv alias }
আমি লুনাথের সাথে একমত হচ্ছি যে এর ব্যবহারকে নিরুৎসাহিত করা, এবং তার সমাধান BASH ব্যবহারকারীদের জন্য পুরোপুরি বৈধ। যাইহোক, আরো পোর্টেবল হতে, command -v
পরিবর্তে ব্যবহার করা হবে:
$ command -v foo >/dev/null 2>&1 || { echo "I require foo but it's not installed. Aborting." >&2; exit 1; }
কমান্ড command
POSIX অনুবর্তী, তার স্পেসিফিকেশন জন্য এখানে দেখুন: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/command.html
নোট: type
POSIX সঙ্গতিপূর্ণ, কিন্তু type -P
হয় না।
এখানে কয়েকটি বিকল্প রয়েছে কিন্তু আমি কোনও দ্রুত এক-মাছ ধরার জন্য অবাক হচ্ছি না, আমার স্ক্রিপ্টগুলির শুরুতে আমি এটি ব্যবহার করেছি: [[ "$(command -v mvn)" ]] || { echo "mvn is not installed" 1>&2 ; exit 1; } [[ "$(command -v java)" ]] || { echo "java is not installed" 1>&2 ; exit 1; }
[[ "$(command -v mvn)" ]] || { echo "mvn is not installed" 1>&2 ; exit 1; } [[ "$(command -v java)" ]] || { echo "java is not installed" 1>&2 ; exit 1; }
এই এখানে নির্বাচিত উত্তর এবং অন্য উত্স উপর ভিত্তি করে (এবং আমি একটু কাছাকাছি বাজানো)।
এই অন্যদের জন্য সহজ হবে আশা করি।
এটি নির্ভর করে যে আপনি এটি জানতে চান কিনা এটি $PATH
পরিবর্তনশীল ডিরেক্টরিগুলির একটিতে বিদ্যমান কিনা বা আপনি এটির সম্পূর্ণ অবস্থান জানেন কিনা। যদি আপনি $PATH
পরিবর্তনশীল কিনা তা জানতে চান তবে ব্যবহার করুন
if which programname >/dev/null; then
echo exists
else
echo does not exist
fi
অন্যথায় ব্যবহার করুন
if [ -x /path/to/programname ]; then
echo exists
else
echo does not exist
fi
পুনঃনির্দেশ /dev/null/
প্রথম উদাহরণে which
প্রোগ্রামটি আউটপুটকে দমন করে।
কোন প্রোগ্রাম বিদ্যমান কিনা তা পরীক্ষা করে দেখতে চান এবং প্রকৃতপক্ষে একটি প্রোগ্রাম, একটি বিশ নির্মিত অন্তর্নিহিত কমান্ড নয় , তাহলে command
, type
এবং hash
পরীক্ষার জন্য উপযুক্ত নয় কারণ এটি বিল্ট-ইন কমান্ডগুলির জন্য 0 প্রস্থান স্থিতিটি সকল প্রত্যাবর্তন করে।
উদাহরণস্বরূপ, সময় প্রোগ্রাম রয়েছে যা বিল্ট ইন কমান্ডের চেয়ে আরও বৈশিষ্ট্যগুলি সরবরাহ করে। প্রোগ্রাম বিদ্যমান কিনা তা পরীক্ষা করার জন্য, আমি নিম্নলিখিত উদাহরণ হিসাবে which
ব্যবহার করে সুপারিশ করবে:
# first check if the time program exists
timeProg=`which time`
if [ "$timeProg" = "" ]
then
echo "The time program does not exist on this system."
exit 1
fi
# invoke the time program
$timeProg --quiet -o result.txt -f "%S %U + p" du -sk ~
echo "Total CPU time: `dc -f result.txt` seconds"
rm result.txt
কোন বহিরাগত type
কমান্ড উপলব্ধ নেই ( here প্রদত্ত হিসাবে নেওয়া here ), আমরা POSIX সম্মতি env -i sh -c 'type cmd 1>/dev/null 2>&1'
:
# portable version of Bash's type -P cmd (without output on stdout)
typep() {
command -p env -i PATH="$PATH" sh -c '
export LC_ALL=C LANG=C
cmd="$1"
cmd="`type "$cmd" 2>/dev/null || { echo "error: command $cmd not found; exiting ..." 1>&2; exit 1; }`"
[ $? != 0 ] && exit 1
case "$cmd" in
*\ /*) exit 0;;
*) printf "%s\n" "error: $cmd" 1>&2; exit 1;;
esac
' _ "$1" || exit 1
}
# get your standard $PATH value
#PATH="$(command -p getconf PATH)"
typep ls
typep builtin
typep ls-temp
ব্যাশ 4.2.24 (2) command -v ls
ব্যবহার করে অন্তত ম্যাক ওএস এক্স 10.6.8 তে একটি সরানো /bin/ls-temp
মেলে না।
প্রোগ্রাম উপস্থিত বা না যদি অবস্থান অনুযায়ী বলতে হবে
if [ -x /usr/bin/yum ]; then
echo This is Centos
fi
বাশের type -P cmd
অনুকরণ করতে আমরা POSIX সম্মিলিত env -i type cmd 1>/dev/null 2>&1
।
man env
# "The option '-i' causes env to completely ignore the environment it inherits."
# In other words, there are no aliases or functions to be looked up by the type command.
ls() { echo 'Hello, world!'; }
ls
type ls
env -i type ls
cmd=ls
cmd=lsx
env -i type $cmd 1>/dev/null 2>&1 || { echo "$cmd not found"; exit 1; }
ব্যাশ বিলিন্স ব্যবহার না করলে কেন?
which programname
...
type -P programname
যদি আপনি লোকগুলি উপরে / নীচের জিনিসগুলিকে কাজ করতে এবং আপনার ব্যাক থেকে চুল টানতে না পান তবে bash -c
ব্যবহার করে একই কমান্ড চালানোর চেষ্টা করুন। শুধু এই সোনাম্যামুলার চকচকে দেখুন, এটি যখন আপনি $ (সাব-কমান্ড) চালান তখন সত্যিই ঘটছে:
প্রথম। এটা আপনি সম্পূর্ণ ভিন্ন আউটপুট দিতে পারেন।
$ command -v ls
alias ls='ls --color=auto'
$ bash -c "command -v ls"
/bin/ls
দ্বিতীয়ত। এটা আপনি কোন আউটপুট দিতে পারেন।
$ command -v nvm
nvm
$ bash -c "command -v nvm"
$ bash -c "nvm --help"
bash: nvm: command not found
হ্যাশ-বৈকল্পিকটি একটি পিটফল রয়েছে: কমান্ড লাইনের ক্ষেত্রে আপনি উদাহরণ টাইপ করতে পারেন
one_folder/process
প্রক্রিয়া নির্বাহ করা আছে। এর জন্য one_folder এর প্যারেন্ট ফোল্ডার $ PATH হতে হবে। কিন্তু যখন আপনি এই কমান্ডটি হাশ করার চেষ্টা করেন, তখন এটি সর্বদা সফল হবে:
hash one_folder/process; echo $? # will always output '0'
hash
ব্যবহার করার জন্য @ লোহনাথ প্রস্তাব করেছেন , একটি ব্যাশ স্ক্রিপ্টে:
hash foo &> /dev/null
if [ $? -eq 1 ]; then
echo >&2 "foo not found."
fi
এই স্ক্রিপ্টটি hash
চালায় এবং তারপরে সবচেয়ে সাম্প্রতিক কমান্ডের প্রস্থান কোডটি মান $?
সংরক্ষণ করা হলে চেক করে $?
, 1
সমান। hash
যদি foo
না পায়, তাহলে প্রস্থান কোডটি 1
। যদি foo
উপস্থিত থাকে, তাহলে প্রস্থান কোড 0
।
&> /dev/null
hash
থেকে স্ট্যান্ডার্ড ত্রুটি এবং স্ট্যান্ডার্ড আউটপুট পুনঃনির্দেশিত করে যাতে এটি অনস্ক্রীন এবং echo >&2
প্রদর্শিত না হয় echo >&2
স্ট্যান্ডার্ড ত্রুটির বার্তাটি লিখে।
hash foo 2>/dev/null
: zsh, bash, dash এবং ash এর সাথে কাজ করে।
type -p foo
: এটি zsh, bash এবং ash (busybox) সহ কাজ করে বলে মনে হচ্ছে, কিন্তু ড্যাশ নয় (এটি একটি যুক্তি হিসাবে -p
ব্যাখ্যা করে)।
command -v foo
: zsh, bash, dash, কিন্তু Ash ( -ash: command: not found
) সহ কাজ করে না ( -ash: command: not found
)।
এছাড়াও নোট এবং dash
সঙ্গে builtin
উপলব্ধ নোট।
একাধিক নির্ভরশীলতা জন্য চেক করুন এবং শেষ ব্যবহারকারীদের অবহিত অবস্থা
for cmd in "latex" "pandoc"; do
printf "%-10s" "$cmd"
if hash "$cmd" 2>/dev/null; then printf "OK\n"; else printf "missing\n"; fi
done
নমুনা আউটপুট:
latex OK
pandoc missing
10
সর্বোচ্চ কমান্ড দৈর্ঘ্য সামঞ্জস্য করুন। স্বয়ংক্রিয় নয় কারণ আমি এটি করার জন্য একটি অ-ক্রিয়াবক্স পসিক্স উপায় দেখতে পাচ্ছি না: Bash এ স্পেস বিভাজিত টেবিলের কলামগুলি কীভাবে সাজানো যায়?