यहाँ आप कभी नहीं सोचा था कि आप इसके बारे में जानना कभी नहीं चाहेंगे:
सारांश
बॉर्न जैसी शेल स्क्रिप्ट में एक निष्पादन योग्य का पथनाम प्राप्त करने के लिए (कुछ कैविएट हैं; नीचे देखें):
ls=$(command -v ls)
यह जानने के लिए कि क्या कोई दिया गया आदेश मौजूद है:
if command -v given-command > /dev/null 2>&1; then
echo given-command is available
else
echo given-command is not available
fi
एक इंटरैक्टिव बॉर्न की तरह खोल के संकेत पर:
type ls
whichआदेश सी-शैल से एक टूटी हुई विरासत है और बेहतर बॉर्न की तरह गोले में अकेला छोड़ दिया जाता है।
बक्सों का इस्तेमाल करें
एक स्क्रिप्ट के भाग के रूप में या शैल प्रांप्ट पर अंतःक्रियात्मक रूप से उस जानकारी की तलाश करने में अंतर है।
शेल प्रॉम्प्ट में, विशिष्ट उपयोग मामला है: यह कमांड अजीब तरह से व्यवहार करता है, क्या मैं सही का उपयोग कर रहा हूं? जब मैंने टाइप किया तो वास्तव में क्या हुआ mycmd? क्या मैं आगे देख सकता हूं कि यह क्या है?
उस स्थिति में, आप यह जानना चाहते हैं कि जब आप कमांड को वास्तव में कमांड को लागू किए बिना अपना शेल क्या करते हैं।
शेल स्क्रिप्ट में, यह काफी अलग है। शेल स्क्रिप्ट में कोई कारण नहीं है कि आप यह जानना चाहते हैं कि यदि आप क्या करना चाहते हैं तो यह कहां या क्या है, तो इसे चलाएं। आम तौर पर, आप जो जानना चाहते हैं, वह निष्पादन योग्य का मार्ग है, इसलिए आप इससे अधिक जानकारी प्राप्त कर सकते हैं (जैसे उस के सापेक्ष किसी अन्य फ़ाइल का पथ, या उस पथ पर निष्पादन योग्य फ़ाइल की सामग्री से जानकारी पढ़ें)।
सहभागितापूर्ण तरीके से, आप के बारे में पता करने के लिए चाहते हो सकता है सभीmy-cmd आदेशों सिस्टम पर उपलब्ध, लिपियों में, शायद ही कभी इतना।
उपलब्ध उपकरणों में से अधिकांश (जैसा कि अक्सर होता है) को अंतःक्रियात्मक रूप से उपयोग करने के लिए डिज़ाइन किया गया है।
इतिहास
पहले थोड़ा इतिहास।
70 के दशक के उत्तरार्ध तक शुरुआती यूनिक्स गोले का कोई कार्य या उपनाम नहीं था। केवल निष्पादन में पारंपरिक देख रहे हैं $PATH। csh1978 के आसपास उपनामों को पेश किया (हालांकि मई 1979 में cshपहली बार जारी किया गया था 2BSD), और .cshrcशेल (हर शेल को अनुकूलित करने के लिए उपयोगकर्ताओं के लिए प्रसंस्करण भी , जैसा कि स्क्रिप्ट में इंटरएक्टिव नहीं होने पर भी cshपढ़ता है .cshrc)।
जबकि बॉर्न शेल पहली बार 1979 में यूनिक्स वी 7 में जारी किया गया था, फ़ंक्शन समर्थन केवल बहुत बाद में (एसवीआर 2 में 1984) जोड़ा गया था, और वैसे भी, इसमें कभी भी कुछ rcफ़ाइल नहीं थी ( .profileआपके पर्यावरण को कॉन्फ़िगर करने के लिए, शेल प्रति नहीं )।
csh बॉर्न शेल की तुलना में बहुत अधिक लोकप्रिय हो गया (हालांकि इसमें बॉर्न शेल की तुलना में एक बहुत बुरा सिंटैक्स था) यह इंटरैक्टिव उपयोग के लिए बहुत अधिक सुविधाजनक और अच्छी सुविधाओं को जोड़ रहा था।
में 3BSD(1980), एक whichcsh स्क्रिप्ट के लिए जोड़ा गया है cshउन एक निष्पादन की पहचान में मदद करने के लिए, और यह एक मुश्किल से भिन्न स्क्रिप्ट आप के रूप में मिल सकता है whichकई वाणिज्यिक Unices आजकल (Salaris, HP / UX, AIX या Tru64 की तरह) पर।
वह स्क्रिप्ट उपयोगकर्ता को पढ़ता है ~/.cshrc(जैसे कि सभी cshस्क्रिप्ट तब तक लागू नहीं होती हैं csh -f), और एलियासेस की सूची में दिए गए कमांड नाम (ओं) और $path(जो सरणी के cshआधार पर बनाए रखता है $PATH) को देखता है ।
यहाँ आप जाते हैं, whichउस समय सबसे लोकप्रिय शेल के लिए पहली बार आया cshथा (और 90 के दशक के मध्य तक अभी भी लोकप्रिय था), जो मुख्य कारण है कि यह पुस्तकों में प्रलेखित हुआ और अभी भी व्यापक रूप से उपयोग किया जाता है।
ध्यान दें, यहां तक कि एक cshउपयोगकर्ता के लिए, वह whichcsh स्क्रिप्ट जरूरी नहीं कि आपको सही जानकारी दे। इसे एलियन्स में परिभाषित किया गया है ~/.cshrc, न कि जिन्हें आपने बाद में प्रॉम्प्ट या उदाहरण के लिए sourceकिसी अन्य cshफ़ाइल के द्वारा परिभाषित किया है , और (हालांकि यह एक अच्छा विचार नहीं होगा), PATHको फिर से परिभाषित किया जा सकता है ~/.cshrc।
whichबॉर्न शेल से उस कमांड को चलाना , अभी भी आपके में परिभाषित उपनामों को खोजेगा ~/.cshrc, लेकिन अगर आपके पास कोई नहीं है क्योंकि आप उपयोग नहीं करते हैं csh, तब भी शायद आपको सही उत्तर मिलेगा।
बिलियन typeकमांड के साथ SVR2 में 1984 तक बॉर्न शेल में एक समान कार्यक्षमता नहीं जोड़ी गई थी । तथ्य यह है कि यह builtin है (किसी बाहरी स्क्रिप्ट के विपरीत) मतलब है कि यह कर सकते हैं कि आप सही जानकारी (कुछ हद तक) देने के रूप में यह खोल के आंतरिक भागों तक पहुँच गया है।
प्रारंभिक typeकमांड एक समान समस्या से ग्रस्त थी क्योंकि whichस्क्रिप्ट में यह विफलता विफलता की स्थिति नहीं लौटाती थी यदि कमांड नहीं मिली थी। इसके अलावा, निष्पादन के लिए, इसके विपरीत which, यह कुछ के ls is /bin/lsबजाय सिर्फ /bin/lsस्क्रिप्ट में उपयोग करने के लिए आसान बना दिया है जो कुछ की तरह उत्पादन ।
यूनिक्स संस्करण 8 का (जंगली में जारी नहीं किया गया) बॉर्न शेल का typeनाम बदलकर बनाया गया था whatis। और Plan9 (यूनिक्स के उत्तराधिकारी एक बार होने वाली है) खोल rc(और इस तरह अपने डेरिवेटिव akangaऔर es) है whatisऔर साथ ही।
कोर्न शेल (जिसका एक उपसमूह POSIX sh परिभाषा पर आधारित है), 80 के दशक के मध्य में विकसित हुआ, लेकिन 1988 से पहले व्यापक रूप से उपलब्ध नहीं था, cshबॉर्न शेल के शीर्ष पर कई विशेषताएं (लाइन संपादक, उपनाम ...) जोड़ी गईं। । इसने अपने स्वयं के whenceबिलिन (इसके अलावा type) को जोड़ा, जो कई विकल्पों को ले गया ( जैसे-वर्बोज़ आउटपुट के -vसाथ प्रदान करने के लिए type, और -pकेवल निष्पादन योग्य के लिए देखने के लिए (उपनाम / फ़ंक्शन नहीं ...)।
एटी एंड टी और बर्कले के बीच कॉपीराइट मुद्दों के संबंध में उथल-पुथल के संयोग से, कुछ मुफ्त सॉफ्टवेयर शेल कार्यान्वयन 80 के दशक के उत्तरार्ध में 90 के दशक की शुरुआत में सामने आए। सभी अल्मक्विस्ट शेल (राख, BSDs में बॉर्न शेल के प्रतिस्थापन के लिए), ksh (pdksh), bash(FSF द्वारा प्रायोजित ) का सार्वजनिक डोमेन कार्यान्वयन , zsh1989 और 1991 के बीच में आया।
हालांकि, ऐश का मतलब बॉर्न शेल के लिए एक प्रतिस्थापन था, हालांकि typeबाद में (नेटबीएसडी 1.3 और फ्रीबीएसडी 2.3 में) एक बिलिन नहीं था , हालांकि यह था hash -v। OSF / 1 /bin/shमें एक typeबिल्डिन था जो हमेशा OSF / 1 v3.x तक 0 लौटाता था। पथ प्रिंट करने के लिए एक विकल्प bashनहीं whenceजोड़ा गया ( जैसा होगा ) और सभी मिलान आदेशों को रिपोर्ट करने के लिए। बनाया निर्मित और एक जोड़ा आदेश की तरह कार्य कर रहा है । उन सभी को है।-ptypetype -pwhence -p-atcshwhichwherebashtype -azsh
fishखोल (2005) एक है typeआदेश एक समारोह के रूप में लागू।
इस whichबीच csh स्क्रिप्ट को NetBSD से हटा दिया गया था (क्योंकि यह tcsh में बनाया गया था और अन्य गोले में ज्यादा इस्तेमाल नहीं किया गया था), और इसमें जो फंक्शनलिटी जोड़ी गई है whereis(जब इनवॉइस किया जाता है which, तो whereisऐसा व्यवहार करता है कि whichसिवाय इसके कि यह केवल एग्जीक्यूटिव दिखता है $PATH)। OpenBSD और FreeBSD में, whichC में लिखे एक को भी बदल दिया गया जो $PATHकेवल कमांड में दिखता है ।
क्रियान्वयन
whichविभिन्न सिंटैक्स और व्यवहार के साथ विभिन्न यूनियनों पर एक कमांड के दर्जनों कार्यान्वयन हैं।
लिनक्स पर (बिल्टइन के बगल में tcshऔर zsh) हम कई कार्यान्वयन पाते हैं। उदाहरण के लिए हाल ही में डेबियन सिस्टम पर, यह एक साधारण पोसिक्स शेल स्क्रिप्ट है जो कमांड में दिखता है $PATH।
busyboxएक whichकमांड भी है ।
वहाँ एक है GNU whichजो शायद सबसे असाधारण है। यह विस्तारित करने का प्रयास करता है कि whichcsh स्क्रिप्ट ने अन्य गोले के लिए क्या किया है: आप इसे बता सकते हैं कि आपके उपनाम और कार्य क्या हैं ताकि यह आपको एक बेहतर उत्तर दे सके (और मेरा मानना है कि कुछ लिनक्स वितरणों ने इसके लिए कुछ वैश्विक उपनाम सेट किए हैं bash) ।
zshनिष्पादकों के मार्ग का विस्तार करने के लिए ऑपरेटरों के एक जोड़े हैं : = फ़ाइल नाम विस्तार ऑपरेटर और :cइतिहास विस्तार संशोधक (यहाँ पैरामीटर विस्तार पर लागू ):
$ print -r -- =ls
/bin/ls
$ cmd=ls; print -r -- $cmd:c
/bin/ls
zsh, zsh/parametersमॉड्यूल में commandsसाहचर्य सारणी के रूप में कमांड हैश तालिका बनाता है :
$ print -r -- $commands[ls]
/bin/ls
whatisउपयोगिता (यूनिक्स वी 8 बॉर्न शैल या योजना 9 में एक को छोड़कर rc/ es) वास्तव में संबंधित नहीं है यह केवल प्रलेखन के लिए के रूप में (whatis डेटाबेस greps, उस आदमी पेज सार 'है)।
whereisको 3BSDउसी समय में भी जोड़ा गया था, जैसा whichकि इसमें लिखा गया था C, न cshकि एक ही समय में देखने के लिए उपयोग किया जाता है, निष्पादन योग्य, मैन पेज और स्रोत लेकिन वर्तमान परिवेश पर आधारित नहीं है। तो फिर, कि एक अलग जरूरत का जवाब।
अब, मानक मोर्चे पर, POSIX command -vऔर -Vकमांड निर्दिष्ट करता है (जो POSIX.2008 तक वैकल्पिक हुआ करता था)। UNIX typeकमांड निर्दिष्ट करता है (कोई विकल्प नहीं)। ऐसा इसलिए है सब ( where, which, whenceकिसी भी मानक में निर्दिष्ट नहीं कर रहे हैं)
कुछ संस्करण तक, typeऔर command -vलिनक्स स्टैंडर्ड बेस स्पेसिफिकेशन में वैकल्पिक थे , जो बताता है कि उदाहरण के लिए posh(हालांकि pdkshदोनों के आधार पर ) के कुछ पुराने संस्करण या तो नहीं थे। command -vकुछ बॉर्न शेल कार्यान्वयन (जैसे सोलारिस पर) में भी जोड़ा गया था।
स्थिति आज
स्थिति आजकल वह यह है कि typeऔर command -vसब बॉर्न की तरह गोले (हालांकि, के रूप में @jarno द्वारा बताया गया है, ध्यान दें में चेतावनी / बग में सर्वत्र हैं bashजब POSIX मोड या Almquist के कुछ वंश में नहीं टिप्पणी में नीचे शैल)। tcshएकमात्र शेल है जहां आप उपयोग करना चाहेंगे which(जैसा कि वहाँ नहीं typeहै और whichबिलिन है)।
के अलावा अन्य के गोले में tcshऔर zsh, whichआप जब तक वहाँ कोई अन्य नाम या समारोह है कि इसी नाम से हमारे में से किसी में है के रूप में दिया निष्पादन के पथ बता सकते हैं ~/.cshrc, ~/.bashrcया किसी खोल स्टार्टअप फ़ाइल और आप परिभाषित नहीं करते $PATHअपने में ~/.cshrc। यदि आपके पास इसके लिए एक उपनाम या फ़ंक्शन परिभाषित है, तो यह आपको इसके बारे में नहीं बता सकता है, या आपको गलत बात बता सकता है।
यदि आप किसी दिए गए नाम से सभी कमांड के बारे में जानना चाहते हैं, तो पोर्टेबल कुछ भी नहीं है। आप का उपयोग करेंगे whereमें tcshया zsh, type -aमें bashया zsh, whence -aksh93 में और अन्य गोले में, आप उपयोग कर सकते हैं typeसंयोजन में साथ which -aजो काम कर सकते हैं।
अनुशंसाएँ
एक निष्पादन योग्य के लिए पथनाम प्राप्त करना
अब, एक स्क्रिप्ट में एक निष्पादन योग्य का पथनाम प्राप्त करने के लिए, कुछ चेतावनी हैं:
ls=$(command -v ls)
यह करने का मानक तरीका होगा।
हालांकि कुछ मुद्दे हैं:
- इसे क्रियान्वित किए बिना निष्पादन योग्य का मार्ग जानना संभव नहीं है। सभी
type, which, command -v... सभी उपयोग heuristics पथ पता लगाने के लिए। वे $PATHघटकों के माध्यम से लूप करते हैं और पहली गैर-निर्देशिका फ़ाइल पाते हैं जिसके लिए आपने अनुमति दी है। हालाँकि, शेल के आधार पर, जब कमांड को निष्पादित करने की बात आती है, तो उनमें से कई (बॉर्न, एटी एंड टी केश, ज़श, ऐश ...) सिर्फ़ उन्हें $PATHतब तक निष्पादित करेगा जब तक कि execveसिस्टम कॉल एक त्रुटि के साथ वापस नहीं आता। । उदाहरण के लिए यदि $PATHइसमें सम्मिलित है /foo:/barऔर आप निष्पादित करना चाहते हैं ls, तो वे पहले निष्पादित करने का प्रयास करेंगे /foo/lsया यदि वह विफल रहता है /bar/ls। अब का निष्पादन/foo/lsविफल हो सकता है क्योंकि आपके पास निष्पादन की अनुमति नहीं है, लेकिन कई अन्य कारणों से भी, जैसे कि यह एक वैध निष्पादन योग्य नहीं है। command -v lsरिपोर्ट करेंगी /foo/lsकि क्या आपके पास निष्पादन की अनुमति है /foo/ls, लेकिन यदि lsवास्तव में वैध निष्पादन योग्य नहीं है /bar/lsतो चल सकता /foo/lsहै।
- अगर
fooएक बिलिन या फ़ंक्शन या उपनाम है, तो command -v fooरिटर्न foo। जैसे कुछ गोले ash, pdkshया zsh, यह भी वापस आ सकता है fooयदि $PATHखाली स्ट्रिंग शामिल है और fooवर्तमान निर्देशिका में एक निष्पादन योग्य फ़ाइल है। ऐसी कुछ परिस्थितियाँ हैं, जहाँ आपको इसे ध्यान में रखना होगा। उदाहरण के लिए ध्यान रखें कि बिल्डरों की सूची शेल कार्यान्वयन के साथ बदलती है (उदाहरण के लिए, mountकभी-कभी बिजीबॉक्स के लिए बिलिन है sh), और उदाहरण के bashलिए पर्यावरण से फ़ंक्शन प्राप्त कर सकते हैं।
- यदि
$PATHसापेक्ष पथ घटक होते हैं (आमतौर पर .या खाली स्ट्रिंग जो दोनों वर्तमान निर्देशिका को संदर्भित करते हैं, लेकिन कुछ भी हो सकता है), शेल के आधार पर, command -v cmdएक निरपेक्ष पथ का उत्पादन नहीं कर सकता है। इसलिए आपके द्वारा चलाए command -vजा रहे समय पर प्राप्त होने वाला मार्ग आपके बाद cdकहीं और मान्य नहीं होगा ।
- उपाख्यानात्मक: ksh93 खोल के साथ, अगर
/opt/ast/bin(हालांकि कि सटीक पथ विभिन्न प्रणालियों मेरा मानना है कि पर भिन्न हो सकते हैं) आप में है $PATH, ksh93 उपलब्ध कुछ अतिरिक्त builtins (कर देगा chmod, cmp, cat...), लेकिन command -v chmodवापस आ जाएगी /opt/ast/bin/chmod, भले ही उस मार्ग नहीं करता ' टी मौजूद है।
यह निर्धारित करना कि क्या कोई आदेश मौजूद है
यह जानने के लिए कि क्या कोई दी गई आज्ञा मानक रूप से मौजूद है, आप यह कर सकते हैं:
if command -v given-command > /dev/null 2>&1; then
echo given-command is available
else
echo given-command is not available
fi
जहां एक का उपयोग करना चाहते हो सकता है which
(t)csh
में cshऔर tcsh, आप ज्यादा विकल्प नहीं है। में tcsh, यह ठीक है जैसा whichकि बिल्टइन है। इसमें csh, वह सिस्टम whichकमांड होगा, जो कुछ मामलों में आप जो चाहते हैं वह नहीं कर सकते हैं।
केवल कुछ गोले में आदेश खोजें
ऐसा मामला जहां इसका उपयोग करने का कोई मतलब हो सकता whichहै, यदि आप एक कमांड का रास्ता जानना चाहते हैं, तो संभावित शेल बिल्डरों या कार्यों को अनदेखा करना bash, csh(नहीं tcsh) dash, या Bourneशेल स्क्रिप्ट, जो कि शेल whence -p(जैसे kshया zsh) नहीं है , command -ev(जैसे yash), whatis -p( rc, akanga) या एक बिलिन which(जैसे tcshया zsh) सिस्टम पर जहां whichउपलब्ध है और cshस्क्रिप्ट नहीं है ।
यदि उन शर्तों को पूरा किया जाता है, तो:
echo=$(which echo)
आप पहली बार के पथ देना होगा echoमें $PATH(कोने मामलों को छोड़कर), चाहे echoकोई शेल भी निर्मित / उर्फ / फंक्शन है या नहीं होता है।
अन्य गोले में, आप पसंद करेंगे:
- zsh :
echo==echoया echo=$commands[echo]याecho=${${:-echo}:c}
- ksh , zsh :
echo=$(whence -p echo)
- यश :
echo=$(command -ev echo)
- आर सी , akanga :
echo=`whatis -p echo`(रिक्तियों के साथ रास्तों में से सावधान रहना)
- मछली :
set echo (type -fp echo)
ध्यान दें कि यदि आप जो करना चाहते हैं , उस कमांड को चलाना है echo, तो आपको इसका रास्ता निकालना नहीं है, आप बस कर सकते हैं:
env echo this is not echoed by the builtin echo
उदाहरण के लिए, tcshबिलिन का whichउपयोग करने से रोकने के लिए :
set Echo = "`env which echo`"
जब आपको बाहरी आदेश की आवश्यकता होती है
एक और मामला जहां आप उपयोग करना चाह सकते हैं which, जब आपको वास्तव में बाहरी कमांड की आवश्यकता होती है । POSIX के लिए आवश्यक है कि सभी शेल बिल्डिंग्स (जैसे command) बाहरी कमांड के रूप में भी उपलब्ध हों, लेकिन दुर्भाग्य से यह commandकई प्रणालियों के लिए ऐसा नहीं है । उदाहरण के लिए, commandलिनक्स आधारित ऑपरेटिंग सिस्टम पर कमांड खोजना दुर्लभ है, जबकि उनमें से अधिकांश में एक whichकमांड है (हालांकि विभिन्न विकल्पों और व्यवहारों के साथ अलग-अलग हैं)।
मामले जहाँ आप एक बाहरी कमांड चाहते हो सकता है जहाँ भी आप एक POSIX शेल को लागू किए बिना एक कमांड निष्पादित करेंगे।
system("some command line"), popen()... सी या विभिन्न भाषाओं के कार्यों कि कमांड लाइन पार्स करने के लिए एक खोल आह्वान, इसलिए करते हैं system("command -v my-cmd")उन में काम करते हैं। इसका एक अपवाद यह होगा कि perlयदि कोई शेल विशेष वर्ण (अंतरिक्ष के अलावा) को नहीं देखता है तो शेल को कैसे अनुकूलित किया जाएगा । यह भी इसके backtick ऑपरेटर पर लागू होता है:
$ perl -le 'print system "command -v emacs"'
-1
$ perl -le 'print system ":;command -v emacs"'
/usr/bin/emacs
0
$ perl -e 'print `command -v emacs`'
$ perl -e 'print `:;command -v emacs`'
/usr/bin/emacs
इसके बाद के :;संस्करण perlवहाँ एक खोल आह्वान करने के लिए मजबूर करता है। उपयोग करके which, आपको उस ट्रिक का उपयोग नहीं करना होगा।
whichएक इंटरैक्टिव शेल संदर्भ मान रहे हैं। यह प्रश्न टैग / पोर्टेबिलिटी है। इसलिए मैं इस संदर्भ में प्रश्न की व्याख्या करता हूं कि "whichकिसी दिए गए नाम के पहले निष्पादन योग्य को खोजने के बजाय क्या उपयोग करना है$PATH"। अधिकांश जवाब और कारणwhichउपनामों, बिल्डरों और कार्यों से निपटने के लिए हैं, जो कि अधिकांश वास्तविक दुनिया में पोर्टेबल शेल स्क्रिप्ट सिर्फ अकादमिक रुचि के हैं। शेल स्क्रिप्ट चलाने के दौरान स्थानीय रूप से परिभाषित उपनामों को विरासत में नहीं मिलता है (जब तक कि आप इसे स्रोत नहीं करते.)।