धमाके की गूंज कैसे!


59

मैंने echoएक फ़ाइल में सामग्री को एक संपादक द्वारा खोलने के बजाय, एक स्क्रिप्ट बनाने की कोशिश की

echo -e "#!/bin/bash \n /usr/bin/command args"  > .scripts/command

उत्पादन :

बैश:! / बिन / बैश: घटना नहीं मिली

मैंने इस अजीब व्यवहार को धमाके से अलग कर दिया है ।

$ echo !
!  

$ echo "!"
bash: !: event not found

$ echo \#!
#!

$ echo \#!/bin/bash
bash: !/bin/bash: event not found
  • धमाका क्यों हो रहा है?
  • ये "घटनाएं" क्या हैं जो बाश को संदर्भित करती हैं?
  • मैं इस समस्या को कैसे हल करूं और स्क्रीन या मेरी फ़ाइल पर "#? / Bin / bash" प्रिंट करूं?

जवाबों:


59

सिंगल कोट्स का उपयोग करके देखें।

echo -e '#!/bin/bash \n /usr/bin/command args'  > .scripts/command

echo '#!'

echo '#!/bin/bash'

समस्या इसलिए हो रही है क्योंकि बैश /! बिन / बैश के लिए अपना इतिहास खोज रहा है। सिंगल कोट्स का प्रयोग इस व्यवहार से बच जाता है।


3
यह स्ट्रिंग प्रक्षेप को भी निष्क्रिय करता है :(
हब्रो

यही तो बात है! आप दोहरे उद्धरण चिह्नों का उपयोग करके समान इको कमांड में अन्य तर्क जोड़ सकते हैं और उन हिस्सों पर प्रक्षेप कर सकते हैं।
रिचम

3
आप bash में C स्टाइल स्ट्रिंग का उपयोग कर सकते हैं $''। उदाहरण के लिए echo $'1!\n2!\n3!\n'प्रत्येक संख्या में एक धमाके और एक नई पंक्ति के बाद प्रिंट होता है।
स्पेलुफो

1
एक सिंगल-लाइन स्ट्रिंग में प्रवेश करते समय सिंगल कोट्स में धमाका करने से मुझे मदद नहीं मिली:! बैश — सिंगल कोट्स धमाके से बच नहीं सकते (असली के लिए)
17

1
@kbolino आप सही हैं। तो पूर्ण उदाहरण स्ट्रिंग होगा: echo '0123'"$var"'456'दो उद्धरणों पर ध्यान दें, एकल उद्धरणों के दो जोड़े और दोहरे उद्धरणों की एक जोड़ी।
फिएट

16

जैसा कि रिचम ने कहा , बैश एक इतिहास मैच करने की कोशिश कर रहा है । इससे बचने का एक और तरीका यह है कि आप धमाके से बच जाएँ \:

$ echo \#\!/bin/bash
#!/bin/bash

हालांकि सावधान रहें कि दोहरे उद्धरण चिह्नों के अंदर, \हटाया नहीं गया है:

$ echo "\!"
\!

8
बाश में, "\!"वास्तव में \!, !पोसिक्स अनुपालन के लिए माना जाता है , नहीं ।
मिकेल

@ मिकेल सिघ। Zsh और पार्टी के बीच इतने सारे मतभेद
माइकल Mrozek

मल्टीलाइन स्ट्रिंग में प्रवेश करते समय भी यह काम करता है। याद रखना 1. धमाके में प्रवेश करने पर एक स्ट्रिंग के बाहर होना और 2. इस विधि का उपयोग करना (बैकस्लैश) अधिकांश परिदृश्यों में कम से कम आश्चर्य के साथ काम करना लगता है।
बिंकी

1
यह ध्यान रखना उपयोगी होगा कि किसी स्क्रिप्ट को निष्पादित करते समय बैश इतिहास खोज नहीं करता है, इसलिए वहां इसके लिए कुछ विशेष करने की आवश्यकता नहीं है।
बिंकी

वहाँ कोई वाक्यविन्यास है !कोई जादू व्यवहार के साथ बस दोहरे उद्धरण चिह्नों के अंदर भागने के लिए ? यह नट है ...
लस्सी

13

!एक इतिहास प्रतिस्थापन शुरू होता है (एक "घटना" कमांड इतिहास में एक पंक्ति है); उदाहरण !lsके लिए अंतिम कमांड लाइन से संबंधित है ls, और !?fooअंतिम कमांड लाइन से संबंधित है foo। आप विशिष्ट शब्द भी निकाल सकते हैं (उदाहरण !!:1पिछले कमांड के पहले शब्द को संदर्भित करता है) और बहुत कुछ; विवरण के लिए मैनुअल देखें।

यह सुविधा उन दिनों की पिछली कमांड्स को जल्दी याद करने के लिए आविष्कार की गई थी जब कमांड लाइन संस्करण आदिम था। आधुनिक गोले (कम से कम बाश और zsh) और कॉपी-और-पेस्ट के साथ, इतिहास विस्तार उतना उपयोगी नहीं है जितना पहले हुआ करता था - यह अभी भी उपयोगी है, लेकिन आप इसके बिना प्राप्त कर सकते हैं।

आप परिवर्तन कर सकते हैं कि कौन सा वर्ण histcharsचर को सेट करके इतिहास प्रतिस्थापन को ट्रिगर करता है; यदि आप शायद ही कभी इतिहास प्रतिस्थापन का उपयोग करते हैं, तो आप उदाहरण के लिए सेट कर सकते हैं histchars='¡^'ताकि ¡इसके बजाय इतिहास का विस्तार हो सके !। आप फीचर को पूरी तरह से बंद भी कर सकते हैं set +o histexpand


3

इतिहास विस्तार को किसी विशेष कमांड लाइन पर निष्क्रिय करने में सक्षम होने के लिए, आप निम्न spaceके 3 वर्ण के रूप में उपयोग कर सकते हैं $histchars:

histchars='!^ '

फिर, यदि आप एक अग्रणी स्थान के साथ अपनी कमांड में प्रवेश करते हैं, तो इतिहास का विस्तार नहीं किया जाएगा।

bash-4.3$ echo "#!/bin/bash"
bash: !/bin/bash: event not found
bash-4.3$  echo "#!/bin/bash"
#!/bin/bash

नोट हालांकि प्रमुख रिक्त स्थान भी उपयोग किया जाता है कि जब $HISTCONTROLहोता है ignorespaceएक तरह से बताने के लिए के रूप में bashइतिहास में एक कमांड लाइन रिकॉर्ड करने के लिए नहीं।

यदि आप दोनों सुविधाओं को अनिश्चित काल तक चाहते हैं, तो आपको दूसरे चरित्र को 3 के चरित्र के रूप में चुनना होगा $histchars। आप वह चाहते हैं जो आपके आदेश की व्याख्या करने के तरीके को प्रभावित न करे। कुछ विकल्प:

  • बैकस्लैश ( \) का उपयोग करना : \echo fooकाम करता है लेकिन इसमें उपनाम या कीवर्ड को अक्षम करने का दुष्प्रभाव है।
  • TAB: इसे पहली स्थिति में सम्मिलित करने के लिए, आपको Ctrl+VTabहालांकि प्रेस करना होगा ।
  • अगर आप दो चाबियाँ टाइपिंग कोई आपत्ति नहीं है, आप किसी भी चरित्र है कि सामान्य रूप से प्रथम स्थान पर दिखाई नहीं करता है (चुन सकते हैं %, @, ?, लेने अपनी खुद की) है और इसके लिए एक खाली उर्फ बनाना:

    histchars='!^%'
    alias %=
    

    फिर उस चरित्र, स्थान और अपने आदेश को दर्ज करें:

    bash-4.3$ % echo !!
    !!
    

(आप एक कमांड रिकॉर्ड नहीं कर पाएंगे, जहां इतिहास प्रतिस्थापन को अक्षम कर दिया गया है। यह भी ध्यान दें कि डिफ़ॉल्ट 3 जी चरित्र $histcharsहै #ताकि इतिहास का विस्तार टिप्पणियों में न किया जाए। यदि आप इसे बदलते हैं, और आप टिप्पणियों को दर्ज करते हैं। प्रॉम्प्ट, आपको इस तथ्य के बारे में पता होना चाहिए कि (अनुक्रम वहां विस्तारित हो सकते हैं)।


2

प्रस्तावित समाधान काम नहीं करते हैं, उदाहरण के लिए, निम्न उदाहरण:

$ bash -c "echo 'hello World!'"
-bash: !'": event not found
$

इस मामले में धमाके को इसके अष्टांगिक ASCII कोड का उपयोग करके मुद्रित किया जा सकता है:

$ bash -c "echo -e 'hello World\0041'"
hello World!
$

1
आपके पहले आदेश में, !दोहरे उद्धरण चिह्नों के बीच है, जहां अन्य उत्तरों से संकेत मिलता है कि यह अपने इतिहास विस्तार अर्थ को बरकरार रखता है। आप उपयोग bash -c 'echo '\''hello World!'\'कर सकते हैं या bash -c "echo 'hello World"\!"'"
गिल्स

-I पैरामीटर के बिना, पर्यावरण को बदला जा सकता है (जैसे आपके ~ / .profile नहीं चलता है)। हालाँकि, कर-आई का मतलब है कि आपके द्वारा .profile से किसी भी आउटपुट को उस कमांड के आउटपुट में कैप्चर किया जाएगा जिसे आप वास्तव में चलाना चाहते हैं।
ब्रेंट

-1

कभी बैश 4.3 के बाद से, अब आप इतिहास विस्तार वर्ण को उद्धृत करने के लिए दोहरे उद्धरण चिह्नों का उपयोग कर सकते हैं:

$ bash --version
GNU bash, version 4.3...
[...]
$ echo "Hello World!"
Hello World!

4
नहीं, यह केवल !उसके बाद है "जो अब विशेष नहीं है। echo "foo!"ठीक है, echo "foo!bar"नहीं है
स्टीफन चेज़लस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.