इंडेंट करते समय कई लाइनों पर एक चर के लिए एक स्ट्रिंग मान कैसे असाइन करें?


54

समस्या:

  1. मुझे एक वैरिएबल को एक मान निर्दिष्ट करना होगा जो शालीनता से लंबा हो।
  2. मेरी स्क्रिप्ट की सभी पंक्तियाँ निश्चित संख्या में कॉलम के अंतर्गत होनी चाहिए।

इसलिए, मैं इसे एक से अधिक लाइन का उपयोग करके असाइन करने का प्रयास कर रहा हूं।

इंडेंट के बिना करना आसान है:

VAR="This displays without \
any issues."
echo "${VAR}"

नतीजा:

This displays without any issues.

हालांकि इंडेंट के साथ:

    VAR="This displays with \
    extra spaces."
    echo "${VAR}"

नतीजा:

This displays with      extra spaces.

मैं इन स्थानों के बिना इसे कैसे आसानी से असाइन कर सकता हूं?

जवाबों:


30

यहाँ मुद्दा यह है कि आप दोहरे कोट्स ("") के साथ चर के आसपास हैं। इसे हटा दें और चीजें ठीक हो जाएंगी।

    VAR="This displays with \
    extra spaces."
    echo ${VAR}

उत्पादन

 This displays with extra spaces.

यहाँ मुद्दा यह है कि एक चर के दोहरे उद्धरण सभी सफेद अंतरिक्ष वर्णों को संरक्षित करता है। यह मामले में इस्तेमाल किया जा सकता है अगर आपको स्पष्ट रूप से इसकी आवश्यकता है।

उदाहरण के लिए,

$ echo "Hello     World    ........ ...            ...."

छप जाएगा

Hello     World    ........ ...            ....

और उद्धरण हटाने पर, इसके अलग

$ echo Hello     World    ........ ...            ....
Hello World ........ ... ....

यहां बैश पाठ में अतिरिक्त रिक्त स्थान निकाल देता है क्योंकि पहले मामले में पूरे पाठ को "एकल" तर्क के रूप में लिया जाता है और इस प्रकार अतिरिक्त रिक्त स्थान को संरक्षित किया जाता है। लेकिन दूसरे मामले में echoकमांड पाठ को 5 तर्कों के रूप में प्राप्त करता है।

आदेशों पर तर्क पारित करते समय एक चर का हवाला देना भी मददगार होगा।

नीचे दिए गए आदेश में, echoकेवल एक तर्क मिलता है"Hello World"

$ variable="Hello World"
$ echo "$variable"

लेकिन नीचे के परिदृश्य के मामले में echoदो तर्क मिलते हैं HelloऔरWorld

$ variable="Hello World"
$ echo $variable

अधिकांश उत्तरों ने अच्छा काम किया, लेकिन यह सबसे सरल था। धन्यवाद!
198 पर Sman865

12
@ Sman865 - कृपया मुझ पर विश्वास करें जब मैं आपको बताता हूं कि यह वास्तव में लगभग निश्चित रूप से सबसे जटिल जवाब है जो यहां पेश किया गया है, और यह ज्यादातर मामलों में गलत भी है - विशेष रूप से इसकी शुरुआती घोषणा में। मूल्य असाइनमेंट के आसपास का कोई भी मुद्दा इसके बाद के विस्तार से संबंधित किसी भी तरह से नहीं हो सकता है - यह सिर्फ पीछे की तरफ है। मुझे खेद है कि कन्नन, लेकिन यह जवाब गलत और गलत दोनों तरह का है। फील्ड-स्प्लिटिंग विस्तार $IFSएक शक्तिशाली और सार्वभौमिक उपकरण है - लेकिन इस तरह से लिखे गए कोड कभी भी किसी भी प्रकार के विश्वसनीय परिणाम नहीं दे सकते हैं।
mikeserv

2
वैरिएबल का विस्तार करते समय उद्धरण का उपयोग करने में विफलता के कारण या बाद में, फ़ाइल नाम विस्तार (किसी भी * ? []) से शुरू होने में समस्या होती है ।
mr.spuratic 11

मैं मानता हूं कि बैश विस्तार से रोकने के लिए चर को दोहरे उद्धरण चिह्नों के अंदर संलग्न करने की आवश्यकता है। लेकिन विशेष मामलों के लिए हम कोड की जटिलता को रोकने के लिए इससे बच सकते हैं।
कन्नन मोहन

1
मैं @mikeserv से सहमत हूं, यह बहुत खराब सलाह है अगर अंकित मूल्य पर लिया जाए। यह अगर परिणाम के बिना इस्तेमाल किया जाएगा तो टूट जाएगा। उदाहरण के लिए, यदि चर को कमांड के तर्क के रूप में पारित किया जाता है, तो आप नहीं चाहते कि प्रत्येक शब्द एक अलग तर्क के रूप में टूट जाए।
haridsv

28

एसुक्सु और मिकाएल बुकास द्वारा दिए गए समाधान ऐसा करने के सामान्य और अधिक पोर्टेबल तरीके हैं।

यहां कुछ bashउपाय दिए गए हैं (जिनमें से कुछ को अन्य गोले में भी काम करना चाहिए, जैसे zsh)। सबसे पहले +=परिशिष्ट ऑपरेटर के साथ (जो पूर्णांक चर में से प्रत्येक के लिए थोड़ा अलग तरीके से काम करता है, एक नियमित चर और एक सरणी)।

text="Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod "
text+="tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, "
text+="quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea ..." 

यदि आप पाठ में newlines (या अन्य व्हाट्सएप / एस्केप) चाहते हैं, तो $''इसके बजाय उद्धरण का उपयोग करें :

text=$'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\n'
text+=$'...'

अगला, printf -vकिसी वैरिएबल को एक स्वरूपित मान असाइन करने के लिए

printf -v text "%s" "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed " \
                    "do eiusmod empor incididunt ut labore et dolore magna aliqua. "\
                    "Ut enim ad minim veniam ..."

यहाँ चाल यह है कि प्रारूप विनिर्देशकों की तुलना में अधिक तर्क हैं, इसलिए अधिकांश printfकार्यों के विपरीत , बैश एक प्रारूप स्ट्रिंग का पुन: उपयोग करता है जब तक कि वह बाहर नहीं निकलता है। आप \nव्हाट्सएप से निपटने के लिए प्रारूप स्ट्रिंग के भीतर रख सकते हैं , या $ '', (या दोनों) का उपयोग कर सकते हैं।

अगला, एक सरणी का उपयोग कर:

text=("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod "
      "tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, "
      "quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea ..." )

आप +=लाइन द्वारा टेक्स्ट अप लाइन बनाने के लिए भी उपयोग कर सकते हैं (नोट करें ()):

text+=("post script")

हालांकि, आपको सरणी को "समतल" करने के लिए याद रखना चाहिए यदि आप संपूर्ण पाठ सामग्री को एक बार में चाहते हैं

echo "$text"      # only outputs index [0], the first line
echo "${text[*]}" # output complete text (joined by first character of IFS)

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

अंत में, " readया readarrayदस्तावेज़" का उपयोग कर :

read -r -d '' text <<-"EOT"
        Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
        tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, 
        quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea ...
EOT

readarray -t textarray <<-"EOT"
        Lorem [...]
EOT  

यहाँ दस्तावेज़ का <<-अर्थ है कि सभी प्रमुख हार्ड टैब इनपुट से हटा दिए गए हैं, इसलिए आपको अपने टेक्स्ट को इंडेंट करने के लिए टैब का उपयोग करना चाहिए। "EOT"शेल विस्तार सुविधाओं को रोकने के बारे में उद्धरण , इसलिए इनपुट का उपयोग शब्दशः किया जाता है। इसके साथ readयह NUL बाइट सीमांकित इनपुट का उपयोग करता है, ताकि यह एक ही बार में न्यूलाइन सीमांकित पाठ को पढ़ ले। साथ readarray(उर्फ mapfile, उपलब्ध के बाद से पार्टी-4.0) यह एक सरणी में पढ़ता है, और -tप्रत्येक पंक्ति पर नई-पंक्तियों स्ट्रिप्स।


1
के readसाथ विकल्प here documentबहुत अच्छा है! अजगर लिपियों को एम्बेड करने और साथ निष्पादित करने के लिए उपयोगी python -c। मैं script=$(cat <here document>)पहले भी करता था, लेकिन read -r -d '' script <here document>बहुत बेहतर है।
haridsv

9

एक विशेष हेरेडोक सिंटैक्स है जो सभी लाइनों की शुरुआत में टैब निकालता है : "<< -" (नोटिस डैश जोड़ा गया)

http://tldp.org/LDP/abs/html/here-docs.html

उदाहरण 19-4। बहु-पंक्ति संदेश, जिसमें टैब दबाए गए हैं

आप इसे इस तरह से उपयोग कर सकते हैं:

v="$(cat <<-EOF
    A
        B
    C
EOF
)"
echo "$v"

नतीजा :

A
B
C

यह केवल टैब के साथ काम करता है, स्पेस नहीं।


यहाँ उबंटू पर, रिवर्स सच है - रिक्त स्थान काम करते हैं, टैब नहीं। \tयदि आपको टैब की आवश्यकता है तो बहुत अच्छा काम करता है। बैकस्लैश पात्रों को सक्षम करने के echo -e "$v"बजाय सिर्फ उपयोग करेंecho "$v"
will-ob-ob

5

शेल को अवांछित लाइनफीड और निम्नलिखित स्थानों को खाने दें:

$ cat weird.sh 
#!/bin/sh

        var1="A weird(?) $(
             )multi line $(
             )text idea. $(
             )PID=$$"

        var2='You can '$(
            )'avoid expansion '$(
            )'too: PID=$$'

        var3='Or mix it: '$(
            )'To insert the PID use $$. '$(
            )"It expands to e.g. $$."

        echo "$var1"
        echo "$var2"
        echo "$var3"
$ sh weird.sh 
A weird(?) multi line text idea. PID=13960
You can avoid expansion too: PID=$$
Or mix it: To insert the PID use $$. It expands to e.g. 13960.

तो यह संभव है ... लेकिन यकीन है कि यह इस समाधान को पसंद या नापसंद करने के लिए स्वाद की बात है ...


3
इनमें से हर एक कांटा है।
mikeserv

5

शायद आप यह कोशिश कर सकते हैं।

          echo "Test" \
               "Test2" \
               "Test3"

5

यह मैं आपको सुझाव देता हूं कि आपको इसे कैसे करना चाहिए, और मैं समझाऊंगा कि क्यों, लेकिन पहले मैं कुछ और बात करना चाहता हूं ...

set -- 'Arg 1: Line 1.' \
       'Arg 2: Line 2.' \
       'and so on for'  \
       'as long as you might like.'
var="$*"

यहाँ कई अन्य सॉल्यूशन दिए गए समाधानों से यह प्रतीत होता है कि आप इसे विस्तार करने के अपने तरीकों में बदलाव करके किसी शेल वेरिएबल की सामग्री को प्रभावित कर सकते हैं। मैं आपको आश्वस्त कर सकता हूं कि ऐसा नहीं है।

    string="some stuff here \
            some more stuff here."
    echo $string ${#string} 
    echo "$string" "${#string}"

आउटपुट

some stuff here some more stuff here. 53
some stuff here                 some more stuff here. 53

जो आप ऊपर देख रहे हैं वह पहले एक फ़ील्ड-स्प्लिट विस्तार है, फिर विस्तार के स्रोत चर के लिए बाइट-काउंट पर एक रिपोर्ट, फिर एक उद्धरण-सीमांकित विस्तार, और एक ही बाइट-काउंट। जबकि आउटपुट भिन्न हो सकता है शेल चर की सामग्री $stringअसाइनमेंट को छोड़कर कभी भी नहीं बदलती है।

क्या अधिक है, अगर आपको समझ नहीं आ रहा है कि यह क्यों है, तो आप बाद में की तुलना में कुछ बहुत ही आश्चर्यजनक आश्चर्य का सामना करने के लिए बाध्य हैं। आइए फिर से कोशिश करें, लेकिन थोड़ा अलग परिस्थितियों में।

    IFS=sf
    echo $string ${#string} 
    echo "$string" "${#string}"

समान $string- अलग वातावरण।

आउटपुट

 ome  tu   here                  ome more  tu   here. 53
some stuff here                 some more stuff here. 53

क्षेत्र में विभाजित क्षेत्र के आधार पर क्षेत्र का विभाजन होता है $IFS। दो प्रकार के सीमांकक हैं - $IFSव्हॉट्सएप और $IFSकुछ भी। डिफ़ॉल्ट $IFSरूप से मान स्पेस टैब न्यूलाइन को असाइन किया जाता है - जो कि तीन संभावित $IFSव्हाट्सएप मान हैं। यह आसानी से बदल जाता है, हालांकि, जैसा कि आप ऊपर देख सकते हैं, और क्षेत्र-विभाजन के विस्तार पर भारी प्रभाव पड़ सकता है।

$IFSव्हॉट्सएप एक एकल क्षेत्र के लिए अनुक्रम से आगे बढ़ेगा - और इस कारण अंतरिक्ष के echoकिसी भी क्रम से युक्त विस्तार का विस्तार $IFSहोता है जब एक अंतरिक्ष में केवल एक ही स्थान का मूल्यांकन होगा - क्योंकि echoरिक्त स्थान पर अपने तर्कों को व्यक्त करता है। लेकिन कोई भी गैर-व्हाट्सएप मान उसी तरह से खत्म नहीं होगा, और प्रत्येक होने वाला सीमांकक हमेशा अपने आप को एक क्षेत्र प्राप्त करता है - जैसा कि ऊपर के सामान विस्तार में देखा जा सकता है ।

यह इसका सबसे बुरा नहीं है। इस पर विचार करें $string

IFS=$space$tab$newline
cd emptydir
    string=" * * * \
             * * * "
    echo $string ${#string}
    echo "$string" "${#string}"    

आउटपुट

* * * * * * 30
 * * *                  * * *  30

ठीक लग रहा है, है ना? ठीक है, चलो पर्यावरण को फिर से बदल दें।

    touch file1 file2 file3 file4 file5
    echo $string ${#string}
    echo "$string" "${#string}"    

आउटपुट

file1 file2 file3 file4 file5 file1 file2 file3 file4 file5 file1 file2 file3 file4 file5 file1 file2 file3 file4 file5 file1 file2 file3 file4 file5 file1 file2 file3 file4 file5 30
 * * *                  * * *  30

ओह।

यदि यह उनसे मेल खा सकता है तो डिफ़ॉल्ट रूप से शेल फाइलनाम ग्लब्स का विस्तार करेगा। यह पैरामीटर विस्तार और उसके पार्स-क्रम में क्षेत्र-विभाजन के बाद होता है और इसलिए किसी भी तरह से बिना तार वाले तार इस तरह से कमजोर होते हैं। set -fयदि आप चाहें तो इस व्यवहार को बंद कर सकते हैं, लेकिन कोई भी POSIX- संगत शेल हमेशा डिफ़ॉल्ट रूप से गोलाकार होगा।

जब आप अपनी इंडेंटेशन वरीयताओं के अनुरूप विस्तार करने के लिए उद्धरण छोड़ते हैं तो यह उस तरह का सामान होता है, जब आप उसके विरुद्ध होते हैं। और फिर भी, हर मामले में, अपने विस्तार के व्यवहार की परवाह किए बिना, $stringहमेशा के लिए वास्तविक मूल्य अभी भी जो कुछ भी था जब आपने इसे आखिरी बार सौंपा था। तो चलिए पहली बात पर वापस आते हैं।

set -- 'Arg 1: Line 1.' \
       'Arg 2: Line 2.' \
       'and so on for'  \
       'as long as you might like.'
var="$*"
echo "$var" "${#var}"

आउटपुट

Arg 1: Line 1. Arg 2: Line 2. and so on for as long as you might like. 70

मेरा मानना ​​है कि शेल सिंटैक्स को आपकी इंडेंटेशन वरीयताओं के लिए अनुकूलित करने का यह एक बहुत ही अच्छा तरीका है। मैं जो कुछ ऊपर कर रहा हूं, वह प्रत्येक व्यक्ति को एक स्ट्रिंग को एक स्थिति पैरामीटर में निर्दिष्ट कर रहा है - जिसे प्रत्येक को संख्या द्वारा संदर्भित किया जा सकता है जैसे - $1या ${33}फिर $varविशेष शेल पैरामीटर का उपयोग करने के लिए अपने समसामयिक मूल्यों को निर्दिष्ट करना $*

यह दृष्टिकोण प्रतिरक्षा नहीं है $IFS, फिर भी। फिर भी, मैं $IFSइस संबंध में एक अतिरिक्त लाभ के लिए इसके संबंध पर विचार करता हूं । विचार करें:

IFS=\ ;space_split="$*"
IFS=/; slash_split="$*";IFS='
';new_line_split="$*"

echo "$space_split"
echo "$slash_split"
echo "$new_line_split"

आउटपुट

Arg 1: Line 1. Arg 2: Line 2. and so on for as long as you might like.
Arg 1: Line 1./Arg 2: Line 2./and so on for/as long as you might like.
Arg 1: Line 1.
Arg 2: Line 2.
and so on for
as long as you might like.

जैसा कि आप देख सकते हैं, पहले बाइट पर $*प्रत्येक arg को अंदर "$@"करता है $IFS। इसलिए $IFSअलग-अलग असाइन किए जाने पर इसके मूल्य को सहेजना प्रत्येक सहेजे गए मूल्य के लिए अलग-अलग क्षेत्र परिसीमन प्राप्त करता है। ऊपर आप जो देख रहे हैं, वह प्रत्येक चर के लिए शाब्दिक मूल्य है। यदि आप चाहते थे कि आप कोई परिसीमन न करें:

IFS=;delimitless="$*"
echo "$delimitless" "${#delimitless}"

आउटपुट

Arg 1: Line 1.Arg 2: Line 2.and so on foras long as you might like. 67



1

यह पथ-प्रकार चर सेट करने के लिए एक प्रकार है:

set -- "${MYDIR}/usr/local/lib" \
      :"${MYDIR}/usr/lib" \
      :"${MYDIR}/lib" \
       "${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
    export LD_LIBRARY_PATH="$*"
    LD_LIBRARY_PATH=$(sed 's/ :/:/g' <<< $LD_LIBRARY_PATH)

setओवरराइट का उपयोग करना $@, जिसे बाद में बचाया जा सकता है और उसका उपयोग किया जा सकता है:

ARGV=("$@")
exec foo "${ARGV[@]}"

LD_LIBRARY_PATH=$(sed 's/ :/:/g' <<< $LD_LIBRARY_PATH)लाइन कोलन के साथ ही संभव पिछली श्वेत रिक्ति से पहले रिक्त स्थान समाप्त करता है। यदि केवल अनुगामी रिक्त स्थान को समाप्त कर रहा है, तो LD_LIBRARY_PATH=${LD_LIBRARY_PATH%% }इसके बजाय उपयोग करें ।

यह संपूर्ण दृष्टिकोण mikeserv के उत्कृष्ट उत्तर पर एक प्रकार है।


0

व्हॉट्सएप पात्रों से डरो मत। अपने बहुस्तरीय पाठ को प्रिंट करने से पहले उन्हें हटा दें।

$ cat ./t.sh
#!/bin/bash

NEED_HELP=1
if [[ $NEED_HELP -eq 1 ]]; then

    lucky_number=$((1 + RANDOM % 10 + 10))

    read -r -d '' text <<'    EOF'
    NAME says hello

    Look at this helpful text:

                                                 * -**
                                 Eyjafjallajokull        Eyjafjallajokull
                            Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull
                        Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull
                    Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull
                Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull
            Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull
        Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull
    Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull

    Don't go away, please rate your experience... It'll just take two minutes.

    EOF
    text=$(echo "$text" | sed -r 's!^\s{4}!!')
    text=$(echo "$text" | sed -r "s!\bNAME\b!$0!") # Bash: text=${text//NAME/$0}
    text=$(echo "$text" | sed -r "s!\btwo\b!$lucky_number!")

    echo "$text"

fi

आउटपुट:

$ ./t.sh
./t.sh says hello

Look at this helpful text:

                                             * -**
                             Eyjafjallajokull        Eyjafjallajokull
                        Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull
                    Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull
                Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull
            Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull
        Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull
    Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull
Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull Eyjafjallajokull

Don't go away, please rate your experience... It'll just take 16 minutes.

<<-टैब वर्णों के साथ एक heredoc का उपयोग करने और अपने 4-स्थान इंडेंटेशन को तोड़ने की आवश्यकता नहीं है ।

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