कैसे बैश में एक चर के लिए एक heredoc मान आवंटित करने के लिए?


374

मेरे पास यह बहु-पंक्ति स्ट्रिंग (उद्धरण शामिल हैं):

abc'asdf"
$(dont-execute-this)
foo"bar"''

मैं बैश में एक हेरेडोक का उपयोग करके इसे एक चर को कैसे निर्दिष्ट करूंगा?

मुझे नई कहानियों को संरक्षित करने की जरूरत है।

मैं स्ट्रिंग में पात्रों से बचना नहीं चाहता, जो कष्टप्रद होगा ...


@ जॉनम - मैंने अभी-अभी एकल-उद्धृत के साथ एक हेरेडोक असाइनमेंट की कोशिश की है 'EOF', ` in the content: if the second line has cd` कमांड के साथ बची हुई लाइनब्रीक के साथ , मुझे वापस मिलता है: " .sh: लाइन एक्स: सीडी: कमांड नहीं मिला "; लेकिन अगर मैं दोहरे उद्धरण "EOF"; तो बैश चर ${A}(वे विस्तारित किए जाते हैं) तार के रूप में संरक्षित नहीं मिलता; लेकिन फिर, लाइन-ब्रेक को संरक्षित किया जाता है - और, मुझे cdदूसरी पंक्ति में ( और 'ईओएफ' और "ईओएफ" दोनों केeval साथ कमांड चलाने में कोई समस्या नहीं है , इसमें संग्रहीत आदेशों का एक सेट चलाने के लिए भी अच्छा लगता है) एक स्ट्रिंग चर )। चीयर्स!
सादाऊ

1
... और मेरी पिछली टिप्पणी में जोड़ने के लिए: टिप्पणी को "#" डबल-क्यूटेड "EOF"वैरिएबल में, यदि कहा जाता है, तो eval $VARशेष सभी स्क्रिप्ट को टिप्पणी करने का कारण होगा, क्योंकि यहां $ VAR को एक एकल पंक्ति के रूप में देखा जाएगा। ; #मल्टीलाइन स्क्रिप्ट में बैश टिप्पणियों का उपयोग करने में सक्षम होने के लिए , eval call: "$ VAR" ` में डबल-उद्धरण भी परिवर्तनशील है ।
सादाऊ

@ सादाऊ: मुझे evalइस तरीकों से समस्या थी , लेकिन इसे नीचे ट्रैक नहीं किया क्योंकि यह कुछ पैकेज का हिस्सा था, जो evalकि कॉन्फ़िगर फ़ाइल में परिभाषित कुछ चर है। त्रुटि संदेश था: /usr/lib/network/network: eval: line 153: syntax error: unexpected end of file। मैं बस एक और समाधान के लिए बंद कर दिया।
गोल्लर रामबलर

जवाबों:


515

आप इसके उपयोग से catबेमेल उपयोग से बच सकते हैं और इसके साथ बेमेल उद्धरणों को बेहतर तरीके से संभाल सकते हैं:

$ read -r -d '' VAR <<'EOF'
abc'asdf"
$(dont-execute-this)
foo"bar"''
EOF

यदि आप इसे प्रतिध्वनित करते समय चर को उद्धृत नहीं करते हैं, तो नए अंक खो जाते हैं। इसे उद्धृत करना उन्हें संरक्षित करता है:

$ echo "$VAR"
abc'asdf"
$(dont-execute-this)
foo"bar"''

यदि आप स्रोत कोड में पठनीयता के लिए इंडेंटेशन का उपयोग करना चाहते हैं, तो कम-थन के बाद डैश का उपयोग करें। इंडेंटेशन केवल टैब (कोई रिक्त स्थान) का उपयोग करके किया जाना चाहिए।

$ read -r -d '' VAR <<-'EOF'
    abc'asdf"
    $(dont-execute-this)
    foo"bar"''
    EOF
$ echo "$VAR"
abc'asdf"
$(dont-execute-this)
foo"bar"''

यदि, इसके बजाय, आप परिणामी चर की सामग्री में टैब को संरक्षित करना चाहते हैं, तो आपको टैब को हटाने की आवश्यकता है IFS। यहाँ डॉक्टर ( EOF) के लिए टर्मिनल मार्कर इंडेंट नहीं होना चाहिए।

$ IFS='' read -r -d '' VAR <<'EOF'
    abc'asdf"
    $(dont-execute-this)
    foo"bar"''
EOF
$ echo "$VAR"
    abc'asdf"
    $(dont-execute-this)
    foo"bar"''

टैब को कमांड लाइन पर दबाकर डाला जा सकता है Ctrl- V Tab। यदि आप एक संपादक का उपयोग कर रहे हैं, जिसके आधार पर, वह भी काम कर सकता है या आपको उस सुविधा को बंद करना पड़ सकता है जो स्वचालित रूप से टैब को रिक्त स्थान में बदल देती है।


117
मुझे लगता है कि यह ध्यान देने योग्य है कि यदि आपके पास आपकी स्क्रिप्ट में set -o errexit(उर्फ set -e) है और आप इसका उपयोग करते हैं तो यह आपकी स्क्रिप्ट को समाप्त कर देगा क्योंकि readयह ईओएफ तक पहुंचने पर एक गैर-शून्य रिटर्न कोड देता है।
मार्क बायर्स

14
@ मार्कर्स: यह उन कारणों में से एक है जिसका मैं कभी उपयोग नहीं करता set -eऔर हमेशा इसके उपयोग के खिलाफ सलाह देता हूं । इसके बजाय उचित त्रुटि हैंडलिंग का उपयोग करना बेहतर है। trapआपका दोस्त है। अन्य दोस्त: elseऔर ||दूसरों के बीच।
अगली सूचना तक रोक दिया गया।

7
क्या इस catतरह के मामले में वास्तव में इससे बचा जा सकता है? एक चर के साथ एक heredoc को सौंपना एक catप्रसिद्ध मुहावरा है। किसी तरह से readथोड़ा लाभ imho के लिए चीजों का उपयोग करते हुए ।
ग्रेगरी पॉक्सोज

6
@ulidtko ऐसा इसलिए है क्योंकि आपके पास dऔर रिक्त स्ट्रिंग के बीच कोई स्थान नहीं है ; कभी-कभी इसके तर्कों को देखने से पहले ही bashपतन -rd''हो जाता है, इसलिए इसे तर्क के रूप में माना जाता है । -rdreadVAR-d
चेपनर

6
इस प्रारूप में, readएक गैर-शून्य निकास कोड के साथ वापस आ जाएगा। यह इस विधि को एक स्क्रिप्ट में आदर्श से कम बनाता है जिसमें एरर चेकिंग इनेबल है (जैसे set -e)।
स्विस

245

catइस तरह अपने चर के उत्पादन को असाइन करने के लिए $ () का उपयोग करें:

VAR=$(cat <<'END_HEREDOC'
abc'asdf"
$(dont-execute-this)
foo"bar"''
END_HEREDOC
)

# this will echo variable with new lines intact
echo "$VAR"
# this will echo variable without new lines (changed to space character)
echo $VAR

एकल-उद्धरणों के साथ END_HEREDOC शुरू करने को सुनिश्चित करें।

ध्यान दें कि वंशानुगत परिसीमन समाप्त END_HEREDOCहोना लाइन पर अकेला होना चाहिए (इसलिए कोष्ठक समाप्त करना अगली पंक्ति में है)।

@ephemientउत्तर के लिए धन्यवाद ।


1
दरअसल, यह कुछ परिस्थितियों में उद्धरण के माध्यम से देता है। मैं पर्ल में आसानी से ऐसा करने में कामयाब रहा ...
नील

32
+1। यह सबसे पठनीय समाधान है, कम से कम मेरी आंखों के लिए। यह पृष्ठ के बाईं ओर चर का नाम छोड़ देता है, बजाय इसे रीड कमांड में एम्बेड करने के।
क्लेटन स्टेनली

12
पीएसए: याद रखें कि चर को नए सिरे को संरक्षित करने के लिए उद्धृत किया जाना चाहिए। echo "$VAR"के बजाय echo $VAR
सेवको 6'14

7
यह ashऔर OpenWRT के साथ अच्छा है जहां readसमर्थन नहीं करता है -d
डेविड एहरमन

3
जिन कारणों से मैं थाह नहीं पा सकता हूं, यह "अनपेक्षित ईओएफ" त्रुटि के साथ विफल हो जाता है यदि आपके पास हेरेडोक में एक अप्रकाशित बैकटिक है।
रेडॉन रोसबोरो

79

यह डेनिस पद्धति की भिन्नता है, लिपियों में अधिक सुरुचिपूर्ण लगती है।

फ़ंक्शन की परिभाषा:

define(){ IFS='\n' read -r -d '' ${1} || true; }

उपयोग:

define VAR <<'EOF'
abc'asdf"
$(dont-execute-this)
foo"bar"''
EOF

echo "$VAR"

का आनंद लें

ps ने गोले के लिए 'रीड लूप' संस्करण बनाया जो समर्थन नहीं करता है read -d। साथ काम करना चाहिए set -euऔर अनपेक्षित backticks , लेकिन बहुत अच्छी तरह से परीक्षण नहीं:

define(){ o=; while IFS="\n" read -r a; do o="$o$a"'
'; done; eval "$1=\$o"; }

1
यह केवल सतही काम करने लगता है। परिभाषित फ़ंक्शन 1 की स्थिति लौटाएगा, और मुझे पूरा यकीन नहीं है कि इसे सही करने की आवश्यकता है।
fny

1
यह स्वीकार किए गए उत्तर से भी बेहतर है, क्योंकि इसे पॉश श के समर्थन के लिए संशोधित किया जा सकता है बश के अलावा ( readफ़ंक्शन में एक लूप, -d ''नए सिरे को संरक्षित करने के लिए आवश्यक बैशवाद से बचने के लिए )।
ELLIOTTCABLE

कैट-इन-ए-सबशेल विकल्प के विपरीत, यह हेरेडोक में अनपेक्षित बैकटिक्स के साथ काम करता है । धन्यवाद!
रेडॉन रोसबोरो

यह समाधान set -eसेट के साथ काम करता है , जबकि चयनित उत्तर नहीं देता है। ऐसा लगता है किhttp://unix.stackexchange.com/a/265151/20650
11

2
@fny ps वापसी स्थिति में लंबे समय तय किया गया है
TTT

36
VAR=<<END
abc
END

काम नहीं करता है क्योंकि आप कुछ को स्टड पुनर्निर्देशित कर रहे हैं जो इसके बारे में परवाह नहीं करता है, अर्थात् असाइनमेंट

export A=`cat <<END
sdfsdf
sdfsdf
sdfsfds
END
` ; echo $A

काम करता है, लेकिन इसमें एक बैक-टिक है जो आपको इसका उपयोग करने से रोक सकता है। इसके अलावा, आपको वास्तव में बैकटिक्स का उपयोग करने से बचना चाहिए, कमांड प्रतिस्थापन नोटेशन का उपयोग करना बेहतर है $(..)

export A=$(cat <<END
sdfsdf
sdfsdf
sdfsfds
END
) ; echo $A

मैंने $ (निष्पादन योग्य) शामिल करने के लिए अपने प्रश्न को अपडेट किया है। इसके अलावा, आप कैसे नई कहानियों को संरक्षित करते हैं?
नील

2
@ l0st3d: इतना करीब ... $(cat <<'END'इसके बजाय उपयोग करें । @ नील: बहुत अंतिम अंतिम पंक्ति वैरिएबल का हिस्सा नहीं होगी, लेकिन बाकी को संरक्षित किया जाएगा।
इफिशिएंट

1
ऐसा लगता नहीं है कि कोई भी नई सूची संरक्षित है। ऊपर दिए गए उदाहरण को देखकर मैं देख रहा हूँ: "sdfsdf sdfsdf sdfsfds" ... आह! लेकिन लेखन echo "$A"(यानी दोहरे उद्धरणों में $ A डालते हुए) और आप नए अंक देखते हैं!
डैरेन कुक

1
@ डारेन: अहा! मैंने नए अंक जारी किए थे, और आउटपुट चर के आसपास के उद्धरणों का उपयोग करके समस्या को ठीक किया। धन्यवाद!
जवदबा

1
दिलचस्प बात यह है पहला उदाहरण के मोड़ के कारण, एक चुटकी में आप इसे इस प्रकार अस्थायी टिप्पणी ब्लॉकों के लिए उपयोग कर सकते हैं: REM=<< 'REM' ... comment block goes here ... REM। या अधिक कॉम्पैक्ट रूप से : << 'REM' ...,। जहाँ "REM" "NOTES" या "SCRATCHPAD", इत्यादि कुछ हो सकता है
Beejor

34

अभी भी कोई समाधान नहीं है जो नई सुर्खियों को बरकरार रखे।

यह सच नहीं है - आप शायद केवल प्रतिध्वनि के व्यवहार से गुमराह हो रहे हैं:

echo $VAR # strips newlines

echo "$VAR" # preserves newlines


5
वास्तव में यह व्यवहार है कि एक चर कैसे काम करता है। उद्धरण के बिना, यह उन्हें अलग-अलग मापदंडों के रूप में सम्मिलित करेगा, अंतरिक्ष को कम कर देगा, जबकि उद्धरण के साथ संपूर्ण चर सामग्री को एक तर्क के रूप में माना जाएगा
Czipperz

11

बंद शाखाओं में नील का जवाब , आप अक्सर सब पर एक वर की जरूरत नहीं है, आप एक चर के रूप में ठीक उसी तरह एक समारोह का उपयोग कर सकते हैं और यह बहुत आसान है इनलाइन या से पढ़ने के लिए readआधारित समाधान।

$ complex_message() {
  cat <<'EOF'
abc'asdf"
$(dont-execute-this)
foo"bar"''
EOF
}

$ echo "This is a $(complex_message)"
This is a abc'asdf"
$(dont-execute-this)
foo"bar"''

9

एक सरणी एक चर है, इसलिए उस स्थिति में मैपफाइल काम करेगा

mapfile y <<z
abc'asdf"
$(dont-execute-this)
foo"bar"''
z

फिर आप इस तरह प्रिंट कर सकते हैं

printf %s "${y[@]}"

3

एक चर के लिए एक heredoc मान असाइन करें

VAR="$(cat <<'VAREOF'
abc'asdf"
$(dont-execute-this)
foo"bar"''
VAREOF
)"

एक कमांड के तर्क के रूप में उपयोग किया जाता है

echo "$(cat <<'SQLEOF'
xxx''xxx'xxx'xx  123123    123123
abc'asdf"
$(dont-execute-this)
foo"bar"''
SQLEOF
)"

जब मैंने पहली विधि की कोशिश की, तो लगता है कि लाइनों के बीच कोई लाइन टर्मिनेटर नहीं है। मेरे लिनक्स मशीन पर किसी प्रकार का विन्यास होना चाहिए?
केमिन झोउ

इसका शायद यह मतलब है कि जब आप अपने चर को प्रतिध्वनित कर रहे थे, तो आपने इसके चारों ओर उद्धरण नहीं दिए थे ... इसे इस तरह आज़माएं:echo "$VAR"
ब्रैड पार्क

1

मैंने पाया कि इसमें NULL के साथ एक स्ट्रिंग पढ़ने के लिए है, इसलिए यहां एक समाधान है जो आप इसे फेंकने वाले कुछ भी पढ़ेंगे । यद्यपि यदि आप वास्तव में NULL के साथ काम कर रहे हैं, तो आपको हेक्स स्तर पर इससे निपटना होगा।

$ बिल्ली> read.dd.sh

read.dd() {
     buf= 
     while read; do
        buf+=$REPLY
     done < <( dd bs=1 2>/dev/null | xxd -p )

     printf -v REPLY '%b' $( sed 's/../ \\\x&/g' <<< $buf )
}

सबूत:

$ . read.dd.sh
$ read.dd < read.dd.sh
$ echo -n "$REPLY" > read.dd.sh.copy
$ diff read.dd.sh read.dd.sh.copy || echo "File are different"
$ 

HEREDOC उदाहरण (^ J, ^ M, ^ I के साथ):

$ read.dd <<'HEREDOC'
>       (TAB)
>       (SPACES)
(^J)^M(^M)
> DONE
>
> HEREDOC

$ declare -p REPLY
declare -- REPLY="  (TAB)
      (SPACES)
(^M)
DONE

"

$ declare -p REPLY | xxd
0000000: 6465 636c 6172 6520 2d2d 2052 4550 4c59  declare -- REPLY
0000010: 3d22 0928 5441 4229 0a20 2020 2020 2028  =".(TAB).      (
0000020: 5350 4143 4553 290a 285e 4a29 0d28 5e4d  SPACES).(^J).(^M
0000030: 290a 444f 4e45 0a0a 220a                 ).DONE

0

Dimo414 के उत्तर के लिए धन्यवाद , यह दिखाता है कि उसका महान समाधान कैसे काम करता है, और दिखाता है कि आपके पास पाठ में उद्धरण और चर आसानी से हो सकते हैं:

उदाहरण आउटपुट

$ ./test.sh

The text from the example function is:
  Welcome dev: Would you "like" to know how many 'files' there are in /tmp?

  There are "      38" files in /tmp, according to the "wc" command

test.sh

#!/bin/bash

function text1()
{
  COUNT=$(\ls /tmp | wc -l)
cat <<EOF

  $1 Would you "like" to know how many 'files' there are in /tmp?

  There are "$COUNT" files in /tmp, according to the "wc" command

EOF
}

function main()
{
  OUT=$(text1 "Welcome dev:")
  echo "The text from the example function is: $OUT"
}

main

पाठ में एक बेजोड़ उद्धरण देखने के लिए यह देखना दिलचस्प होगा कि यह कैसे संभालता है। हो सकता है `बाहर मत करो," $ COUNT "फ़ाइलें हैं" इसलिए एपोस्ट्रोफ़ / एकल उद्धरण चीजों को दिलचस्प बना सकता है।
ड्रैगन 788

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.