का उद्देश्य क्या है: (बृहदान्त्र) GNU बैश बिलिन?


335

एक कमांड का उद्देश्य क्या है जो कुछ भी नहीं करता है, एक टिप्पणी नेता की तुलना में थोड़ा अधिक है, लेकिन वास्तव में एक शेल बिल्ट इन और खुद का है?

यह आपकी लिपियों में लगभग 40% प्रति कॉल द्वारा टिप्पणी डालने से धीमा है, जो संभवतः टिप्पणी के आकार के आधार पर बहुत भिन्न होता है। इसके संभावित कारण केवल मैं ही देख सकता हूं:

# poor man's delay function
for ((x=0;x<100000;++x)) ; do : ; done

# inserting comments into string of commands
command ; command ; : we need a comment in here for some reason ; command

# an alias for `true' (lazy programming)
while : ; do command ; done

मुझे लगता है कि जो मैं वास्तव में खोज रहा हूं वह क्या ऐतिहासिक अनुप्रयोग है जो हो सकता है।



69
@ कालेब - मैंने उससे दो साल पहले यह पूछा था।
amphetamachine

मैं एक कमांड नहीं कहूंगा जो एक विशिष्ट मान लौटाता है "कुछ नहीं करता है।" जब तक कार्यात्मक प्रोग्रामिंग में "कुछ नहीं करना" शामिल है। :-)
लार्स

जवाबों:


415

ऐतिहासिक रूप से , बॉर्न के गोले trueऔर falseअंतर्निहित कमांड के रूप में नहीं थे । trueइसके बजाय बस करने के लिए :और falseकुछ करने के लिए उपनाम दिया गया थाlet 0

:trueप्राचीन बोर्न-व्युत्पन्न गोले के लिए पोर्टेबिलिटी की तुलना में थोड़ा बेहतर है । एक सरल उदाहरण के रूप में, न तो !पाइपलाइन ऑपरेटर और न ही ||सूची ऑपरेटर होने पर विचार करें (जैसा कि कुछ प्राचीन बॉर्न गोले के लिए मामला था)। यह कथन का elseखंड छोड़ देता है ifक्योंकि निकास स्थिति के आधार पर शाखाकरण के लिए एकमात्र साधन है:

if command; then :; else ...; fi

चूंकि ifएक गैर-खाली thenक्लॉज की आवश्यकता होती है और टिप्पणियां गैर-रिक्त के रूप में गणना नहीं :करती हैं , इसलिए यह नो-ऑप के रूप में कार्य करता है।

आजकल (यह है: एक आधुनिक संदर्भ में) आप आमतौर पर :या तो उपयोग कर सकते हैं या true। दोनों POSIX द्वारा निर्दिष्ट हैं, और कुछ trueपढ़ने में आसान लगते हैं। हालांकि एक दिलचस्प अंतर है: :एक तथाकथित POSIX विशेष अंतर्निहित है , जबकि trueएक नियमित रूप से अंतर्निहित है

  • विशेष निर्मित-इन को शेल में बनाया जाना आवश्यक है; नियमित रूप से निर्मित इन्स केवल "आम तौर पर" में निर्मित होते हैं, लेकिन इसकी कड़ाई से गारंटी नहीं है। आमतौर पर अधिकांश प्रणालियों के पथ में :कार्य के साथ नाम का एक नियमित कार्यक्रम नहीं होना चाहिए true

  • संभवतः सबसे महत्वपूर्ण अंतर यह है कि विशेष निर्मित-इन के साथ, अंतर्निहित कमांड द्वारा निर्धारित परिवेश में भी कोई भी चर - कमांड पूरा होने के बाद भी बना रहता है, जैसा कि यहां ksh93 का उपयोग करके दिखाया गया है:

    $ unset x; ( x=hi :; echo "$x" )
    hi
    $ ( x=hi true; echo "$x" )
    
    $

    ध्यान दें कि Zsh इस आवश्यकता को अनदेखा करता है, जैसे कि POSIX संगतता मोड में काम करने के अलावा GNU बैश होता है, लेकिन अन्य सभी प्रमुख "POSIX sh व्युत्पन्न" गोले डैश, ksh93 और mksh सहित इसका निरीक्षण करते हैं।

  • एक और अंतर यह है कि नियमित रूप से निर्मित इन्स के साथ संगत होना चाहिए exec- बैश का उपयोग करके यहां प्रदर्शित:

    $ ( exec : )
    -bash: exec: :: not found
    $ ( exec true )
    $
  • POSIX भी स्पष्ट रूप से नोट करता है जो :इससे तेज हो सकता है true, हालांकि यह निश्चित रूप से कार्यान्वयन-विशिष्ट विवरण है।


क्या आपका मतलब है कि नियमित रूप से निर्मित इन्स के साथ संगत नहीं होना चाहिए exec?
ओल्ड प्रो

1
@ ओल्डप्रो: नहीं, वह सही है जिसमें trueएक नियमित बिलिन है, लेकिन वह इसमें गलत है जो बिलिन के बजाय execउपयोग कर रहा है /bin/true
अगली सूचना तक रोक दिया गया।

1
@ डेनिसविलियम्सन मैं बस उसी तरह जा रहा था जिस तरह से कल्पना की जाती है। निहितार्थ यह है कि नियमित रूप से निर्मित में एक स्टैंडअलोन संस्करण भी मौजूद होना चाहिए।
ormaaj

17
+1 उत्कृष्ट जवाब। मैं अभी भी : ${var?not initialized}एट अल की तरह वैरिएबल के उपयोग के लिए ध्यान देना चाहूंगा ।
त्रिवेणी २०'१४ को

अधिक या कम असंबंधित अनुवर्ती। आपने कहा :कि एक विशेष में बनाया गया है और इसके द्वारा नामित कोई फ़ंक्शन नहीं होना चाहिए। लेकिन :(){ :|: & };:नाम के साथ एक फ़ंक्शन का नामकरण करने वाले कांटा बम का सबसे अधिक देखा जाने वाला उदाहरण नहीं है :?
चोंग

63

मैं इसका उपयोग चर कमांड को आसानी से सक्षम / अक्षम करने के लिए करता हूं:

#!/bin/bash
if [[ "$VERBOSE" == "" || "$VERBOSE" == "0" ]]; then
    vecho=":"     # no "verbose echo"
else
    vecho=echo    # enable "verbose echo"
fi

$vecho "Verbose echo is ON"

इस प्रकार

$ ./vecho
$ VERBOSE=1 ./vecho
Verbose echo is ON

यह एक साफ स्क्रिप्ट के लिए बनाता है। यह '#' के साथ नहीं किया जा सकता है।

इसके अलावा,

: >afile

यह गारंटी देने के सबसे सरल तरीकों में से एक है कि 'afile' मौजूद है, लेकिन 0 लंबाई है।


20
>afileऔर भी सरल है और उसी प्रभाव को प्राप्त करता है।
अर्ल

2
कूल, मैं उस स्क्रिप्ट को सरल बनाने के लिए उस $ vecho ट्रिक का उपयोग करूंगा जिसे मैं बनाए रख रहा हूं।
बार्नीशेमले

5
में बृहदान्त्र उद्धृत करने के लिए क्या लाभ है vecho=":"? सिर्फ पठनीयता के लिए?
लीज

56

के लिए एक उपयोगी अनुप्रयोग है: यदि आप केवल उनके साइड-इफेक्ट के लिए पैरामीटर विस्तार का उपयोग करने में रुचि रखते हैं, बजाय इसके कि वे वास्तव में एक आदेश में अपना परिणाम दे रहे हैं। उस स्थिति में आप पीई का उपयोग तर्क के रूप में या तो करते हैं: या झूठ के आधार पर कि क्या आप 0 या 1 से बाहर निकलने की स्थिति चाहते हैं। एक उदाहरण हो सकता है : "${var:=$1}"। चूंकि :यह बिलियन है, इसलिए यह बहुत तेज होना चाहिए।


2
आप इसका उपयोग अंकगणित के विस्तार के दुष्प्रभावों के लिए भी कर सकते हैं: : $((a += 1))( ++और --ऑपरेटरों को पॉमिक्स के अनुसार लागू करने की आवश्यकता नहीं है।) बाश, ksh और संभव अन्य गोले में आप यह भी कर सकते हैं: ((a += 1))या ((a++))यह POSIX द्वारा निर्दिष्ट नहीं है।
पाबौक

@pabouk हां, यह सब सच है, हालांकि (())एक वैकल्पिक सुविधा के रूप में निर्दिष्ट है। "यदि एक वर्ण क्रम से शुरू होता है" (("एक '$' से पहले अंकगणितीय विस्तार के रूप में शेल द्वारा पार्स किया जाएगा, तो ऐसे शेल जो एक एक्सटेंशन को लागू करते हैं" ((अभिव्यक्ति))) का मूल्यांकन अंकगणितीय अभिव्यक्ति के रूप में किया जा सकता है। "(" एक समूह कमांड के बजाय अंकगणितीय मूल्यांकन के रूप में शुरू करने के रूप में। "
ओरमज

50

:ब्लॉक टिप्पणी के लिए भी हो सकता है (सी भाषा में / * * / के समान)। उदाहरण के लिए, यदि आप अपनी स्क्रिप्ट में कोड का एक ब्लॉक छोड़ना चाहते हैं, तो आप यह कर सकते हैं:

: << 'SKIP'

your code block here

SKIP

3
बुरा विचार। यहाँ दस्तावेज़ के अंदर कोई भी कमांड सबस्टेशन अभी भी संसाधित हैं।
चेपनर

33
ऐसा बुरा विचार नहीं। आप यहाँ पर चर-अतिक्रमण से बच सकते हैं / यहाँ तक कि डॉक्यूमेंट को एकल-उद्धरण के द्वारा डॉक्स में शामिल कर सकते हैं: << << SKIP '
रोंडो

1
IIRC आप भी कर सकते हैं \ एक ही प्रभाव के लिए सीमांकक पात्रों में से किसी एक से बचें: : <<\SKIP
yyny

@zagpoint क्या यह वह जगह है जहाँ पायथन को बहुभाषी टिप्पणियों के रूप में डॉकस्ट्रिंग्स का उपयोग मिलता है?
नीलमणि

31

यदि आप किसी फ़ाइल को शून्य बाइट्स में विभाजित करना चाहते हैं, तो लॉग साफ़ करने के लिए उपयोगी है, इसे आज़माएँ:

:> file.log

16
> file.logसरल है और उसी प्रभाव को प्राप्त करता है।
एम्पेटामाचाइन

55
याह, लेकिन खुश चेहरा यह मेरे लिए क्या करता है:>
एहि टूना

23
@amphetamachine: :>अधिक पोर्टेबल है। कुछ गोले (जैसे मेरे zsh) वर्तमान शेल में एक बिल्ली को ऑटो-इंस्टेंट करते हैं और बिना किसी कमांड के रीडायरेक्ट दिए जाने पर स्टड के लिए सुनते हैं। इसके बजाय cat /dev/null, :बहुत सरल है। अक्सर यह व्यवहार स्क्रिप्ट के बजाय इंटरैक्टिव गोले में भिन्न होता है, लेकिन यदि आप स्क्रिप्ट को इस तरह से लिखते हैं जो इंटरैक्टिव काम करता है, तो कॉपी-पेस्ट द्वारा डीबग करना बहुत आसान है।
कालेब

2
आधुनिक कवच (मान कर और समान रूप से तेज़) : > fileसे अलग true > file(चरित्र की गिनती और प्रसन्न चेहरे से अलग) कैसे होता है ? :true
एडम काट्ज


29

अन्य उत्तरों में दो और उपयोगों का उल्लेख नहीं किया गया है:

लॉगिंग

इस उदाहरण स्क्रिप्ट को लें:

set -x
: Logging message here
example_command

पहली पंक्ति, set -xशेल को चलाने से पहले कमांड का प्रिंट आउट बनाती है। यह काफी उपयोगी निर्माण है। नकारात्मक पक्ष यह है कि सामान्य echo Log messageप्रकार का बयान अब संदेश को दो बार प्रिंट करता है। बृहदान्त्र विधि दौर है कि हो जाता है। ध्यान दें कि आपको अभी भी विशेष पात्रों से बचना होगा जैसे आप करेंगे echo

क्रोन नौकरी शीर्षक

मैंने देखा है कि इसे क्रोन नौकरियों में इस्तेमाल किया जा रहा है, जैसे:

45 10 * * * : Backup for database ; /opt/backup.sh

यह एक क्रॉन जॉब है जो /opt/backup.shहर दिन 10:45 पर स्क्रिप्ट चलाता है । इस तकनीक का लाभ यह है कि यह बेहतर दिखने वाले ईमेल विषयों के लिए बनाता है जब /opt/backup.shकुछ आउटपुट प्रिंट करता है।


डिफ़ॉल्ट लॉग स्थान कहां है? क्या मैं लॉग लोकेशन सेट कर सकता हूं? क्या स्क्रिप्ट / पृष्ठभूमि प्रक्रियाओं के दौरान स्टडआउट में आउटपुट बनाने का उद्देश्य अधिक है?
डोमडम्ब्रोगिया

1
@domdambrogia का उपयोग करते समय set -x, मुद्रित आउट कमांड (जैसे कुछ सहित : foobar) stderr पर जाते हैं।
फ्लि‍म

22

आप इसे ``अपने आउटपुट को प्रदर्शित किए बिना एक कमांड निष्पादित करने के लिए बैकटिक्स ( ) के साथ संयोजन के रूप में उपयोग कर सकते हैं :

: `some_command`

बेशक आप बस कर सकते हैं some_command > /dev/null, लेकिन: -version कुछ कम है।

कहा जा रहा है कि मैं वास्तव में ऐसा करने की सिफारिश नहीं करूंगा क्योंकि यह लोगों को भ्रमित करेगा। यह सिर्फ एक संभव उपयोग के मामले के रूप में दिमाग में आया।


25
यह सुरक्षित नहीं है यदि कमांड आउटपुट के कुछ मेगाबाइट को डंप करने वाला है, क्योंकि शेल आउटपुट को बफ़र करता है और फिर इसे कमांड लाइन तर्क (स्टैक स्पेस) के रूप में ':' में पास करता है।
जुलानियो

15

यह पॉलीग्लॉट कार्यक्रमों के लिए भी उपयोगी है:

#!/usr/bin/env sh
':' //; exec "$(command -v node)" "$0" "$@"
~function(){ ... }

अब यह दोनों एक निष्पादन खोल स्क्रिप्ट है और जिसका अर्थ है: एक जावास्क्रिप्ट कार्यक्रम ./filename.js, sh filename.jsहै, और node filename.jsसब काम।

(निश्चित रूप से थोड़ा अजीब उपयोग, लेकिन फिर भी प्रभावी है।)


अनुरोध के अनुसार कुछ अन्वेषण:

  • शैल-लिपियों का मूल्यांकन लाइन-बाय-लाइन द्वारा किया जाता है; और execकमांड, जब चलाया जाता है, शेल को समाप्त करता है और परिणामी कमांड के साथ इसकी प्रक्रिया को बदल देता है। इसका मतलब यह है कि शेल के लिए, प्रोग्राम इस तरह दिखता है:

    #!/usr/bin/env sh
    ':' //; exec "$(command -v node)" "$0" "$@"
  • जब तक शब्द में कोई पैरामीटर विस्तार या अलियासिंग नहीं हो रही है, तब तक शेल-स्क्रिप्ट में कोई भी शब्द इसके 'अर्थ' को बदले बिना उद्धरणों में लपेटा जा सकता है; इसका अर्थ है कि ':'यह बराबर है :(हमने नीचे वर्णित जावास्क्रिप्ट शब्दार्थ को प्राप्त करने के लिए इसे केवल उद्धरण में लपेटा है)

  • ... और जैसा कि ऊपर वर्णित है, पहली पंक्ति पर पहली कमांड एक नो-ऑप है (यह अनुवाद करता है : //, या यदि आप शब्दों को उद्धृत करना पसंद करते हैं ':' '//'। ध्यान दें कि //यहां कोई विशेष अर्थ नहीं है, जैसा कि जावास्क्रिप्ट में है; यह सिर्फ एक व्यर्थ शब्द है जिसे फेंका जा रहा है।)

  • अंत में, पहली पंक्ति (अर्धविराम के बाद) पर दूसरी कमान, कार्यक्रम का असली मांस है: यह वह execकॉल है जो शेल-स्क्रिप्ट को बदले जाने पर प्रतिस्थापित करता है , बाकी स्क्रिप्ट का मूल्यांकन करने के लिए एनओडी.जेएस प्रक्रिया के साथ ।

  • इस बीच, जावास्क्रिप्ट में पहली पंक्ति, स्ट्रिंग-शाब्दिक ( ':') के रूप में पार्स करती है , और फिर एक टिप्पणी, जिसे हटा दिया जाता है; इस प्रकार, जावास्क्रिप्ट के लिए, कार्यक्रम इस तरह दिखता है:

    ':'
    ~function(){ ... }

    चूंकि स्ट्रिंग-शाब्दिक स्वयं द्वारा एक पंक्ति पर है, यह एक नो-ऑप स्टेटमेंट है, और इस प्रकार प्रोग्राम से छीन लिया गया है; इसका मतलब है कि पूरी लाइन हटा दी गई है, केवल आपके प्रोग्राम-कोड (इस उदाहरण में, function(){ ... }निकाय) को छोड़कर ।


हैलो, क्या आप समझा सकते हैं कि क्या : //;और क्या ~function(){}करते हैं? धन्यवाद:)
Stphane

1
@ स्टेफ़ेन ने ब्रेक-डाउन जोड़ा! के रूप में ~function(){}, यह थोड़ा और अधिक जटिल है। नहीं है एक जोड़े को यहाँ पर उस पर स्पर्श, हालांकि वास्तव में उनमें से कोई भी मेरे संतोष के लिए यह समझाने ... अगर उन सवालों का न तो यह अच्छी तरह से पर्याप्त आप, यहाँ एक सवाल के रूप में यह पोस्ट करने के लिए स्वतंत्र लग रहा है के लिए बताते हैं कि, मैं हो जाएगा अन्य उत्तर एक नए सवाल पर गहराई से जवाब देने के लिए खुश।
ELLIOTTCABLE

1
मैंने ध्यान नहीं दिया node। तो फंक्शन पार्ट सब जावास्क्रिप्ट के बारे में है! मैं IIFE के सामने यूनिरी ऑपरेटर के साथ ओके हूं। मुझे लगा कि यह पहली बार में भी बैश था और वास्तव में आपके पोस्ट का वास्तव में अर्थ नहीं निकला। मैं अब ठीक हूं, «ब्रेक-डाउन» जोड़ने में आपका समय बिताने के लिए धन्यवाद!
स्टीफन

~{ No problem. (= }
18

12

स्व-दस्तावेजीकरण कार्य

आप :किसी फ़ंक्शन में दस्तावेज़ एम्बेड करने के लिए भी उपयोग कर सकते हैं ।

मान लें कि आपके पास एक लाइब्रेरी स्क्रिप्ट है mylib.sh , जो विभिन्न प्रकार के फ़ंक्शन प्रदान करती है। आप या तो लाइब्रेरी को स्रोत बना सकते हैं ( . mylib.shऔर उसके बाद सीधे फ़ंक्शन को कॉल कर सकते हैं lib_function1 arg1 arg2), या अपने नाम स्थान को अव्यवस्थित करने से बचें और लाइब्रेरी को फ़ंक्शन तर्क के साथ लागू करें (mylib.sh lib_function1 arg1 arg2 ) के ।

क्या यह अच्छा नहीं होगा यदि आप mylib.sh --helpमदद पाठ में फ़ंक्शन सूची को मैन्युअल रूप से बनाए रखने के बिना उपलब्ध कार्यों और उनके उपयोग की सूची भी टाइप कर सकते हैं और प्राप्त कर सकते हैं ?

#! / Bin / bash

# सभी "सार्वजनिक" कार्य इस उपसर्ग के साथ शुरू होने चाहिए
LIB_PREFIX = 'lib_'

"# सार्वजनिक" लाइब्रेरी फ़ंक्शन
lib_function1 () {
    : यह फ़ंक्शन दो तर्कों के साथ कुछ जटिल करता है।
    :
    : पैरामीटर:
    : 'arg1 - पहला तर्क ($ 1)'
    : 'arg2 - दूसरा तर्क'
    :
    : परिणाम:
    : " यह जटिल है"

    # वास्तविक फ़ंक्शन कोड यहां से शुरू होता है
}

lib_function2 () {
    : समारोह प्रलेखन

    # फंक्शन कोड यहाँ
}

# सहायता समारोह
--मदद() {
    इको माईलिब v0.0.1
    गूंज
    इको उपयोग: mylib.sh [function_name [args]]
    गूंज
    उपलब्ध उपलब्ध कार्य:
    घोषणापत्र -f | sed -n -e '/ ^' $ LIB_PREFIX '/, / ^} $ / {/ \ (^' $ LIB_PREFIX '\ _ \ _ \ _ (^ [\ t] *: \ _ / {)
        s / ^ \ ('$ LIB_PREFIX'। * \) () / \ n === \ _ = = /? s / ^ [\ t] *: \? ['\' '""]? /? की / [ '\' ' "] \;? \ $ //;? पी}}'
}

# मुख्य कोड
अगर ["$ {BASH_SOURCE [0]}" = "$ {0}"]; फिर
    # पटकथा के बजाय पटकथा को अंजाम दिया गया
    # अनुरोध किए गए फ़ंक्शन या प्रदर्शन सहायता का आह्वान करें
    अगर ["$ (टाइप -t -" $ 1 "2> / देव / नल)" = फ़ंक्शन]; फिर
        "$ @"
    अन्य
        --मदद
    फाई
फाई

कोड के बारे में कुछ टिप्पणियां:

  1. सभी "सार्वजनिक" कार्यों में एक ही उपसर्ग होता है। केवल ये उपयोगकर्ता द्वारा आह्वान किए जाने और सहायता पाठ में सूचीबद्ध होने के लिए हैं।
  2. सेल्फ-डॉक्यूमेंटिंग फीचर पिछले बिंदु पर निर्भर करता है, और declare -fसभी उपलब्ध फ़ंक्शन को एन्यूमरेट करने के लिए उपयोग करता है, फिर उन्हें सीड के माध्यम से केवल उपयुक्त उपसर्ग के साथ फ़ंक्शन प्रदर्शित करने के लिए फ़िल्टर करता है।
  3. अवांछित उद्धरण और व्हाट्सएप को हटाने से रोकने के लिए, एकल उद्धरण में दस्तावेज़ को संलग्न करना एक अच्छा विचार है। पाठ में प्रेषित / उद्धरणों का उपयोग करते समय आपको सावधान रहने की आवश्यकता होगी।
  4. आप लाइब्रेरी उपसर्ग को आंतरिक बनाने के लिए कोड लिख सकते हैं, अर्थात उपयोगकर्ता को केवल टाइप करना होता है mylib.sh function1और इसे आंतरिक रूप से अनुवादित किया जाता है lib_function1। यह पाठक के लिए एक अभ्यास है।
  5. सहायता फ़ंक्शन का नाम "--help" है। यह एक सुविधाजनक (यानी आलसी) दृष्टिकोण है जो लाइब्रेरी इनवोक मैकेनिज्म का उपयोग करता है, ताकि मदद के लिए अतिरिक्त चेक को कोड किए बिना खुद को प्रदर्शित किया जा सके $1। उसी समय, यह आपके नाम स्थान को अव्यवस्थित कर देगा यदि आप पुस्तकालय का स्रोत हैं। यदि आपको वह पसंद नहीं है, तो आप या तो नाम को कुछ बदल सकते हैं lib_helpया वास्तव --helpमें मुख्य कोड के लिए आर्ग की जांच कर सकते हैं और मैन्युअल रूप से सहायता फ़ंक्शन को लागू कर सकते हैं।

4

मैंने एक स्क्रिप्ट में इस उपयोग को देखा और सोचा कि यह स्क्रिप्ट के भीतर बेसन को लागू करने के लिए एक अच्छा विकल्प है।

oldIFS=$IFS  
IFS=/  
for basetool in $0 ; do : ; done  
IFS=$oldIFS  

... यह कोड के लिए एक प्रतिस्थापन है: basetool=$(basename $0)


मुझे पसंद हैbasetool=${0##*/}
अमित नायडू
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.