क्या heredoc (EOF) में इको-एन के समान कुछ है?


12

मैं एक विशाल स्क्रिप्ट-फैक्ट्री स्क्रिप्ट पर लिख रहा हूं, जो मेरे सर्वर के लिए बहुत सारे रखरखाव स्क्रिप्ट का निर्माण कर रही है।

अब तक मैं कुछ पंक्तियाँ लिखता हूँ जो echo -neउदाहरण के साथ एक पंक्ति में लिखी जानी चाहिए

echo -n "if (( " | sudo tee -a /usr/local/bin/upgradeAllServers &> /dev/null

# Generate exitCode check for each Server
IFS=" "
COUNT=0
while read -r name ipAddr
do
    if(($COUNT != 0))
    then
        echo -n " || " | sudo tee -a /usr/local/bin/upgradeAllServers &> /dev/null
    fi

    echo -n "(\$"$name"_E != 0 && \$"$name"_E != 1)" | sudo tee -a /usr/local/bin/upgradeAllServers &> /dev/null

    COUNT=$((COUNT+1))

    JOBSDONE=$((JOBSDONE+1))
    updateProgress $JOBCOUNT $JOBSDONE
done <<< "$(sudo cat /root/.virtualMachines)"

echo " ))" | sudo tee -a /usr/local/bin/upgradeAllServers &> /dev/null

यह मुझे उत्पन्न करता है (यदि मेरी कॉन्फ़िगरेशन फ़ाइल में उदाहरण के लिए 2 सर्वर हैं) जैसे कोड

if (( ($server1_E != 0 && $server1_E != 1) || ($server2_E != 0 && $server2_E != 1) ))

अन्य सभी कोड ब्लॉक जिन्हें मुझे कोड के इनलाइन लेखन की आवश्यकता नहीं है, मैं हेरेडोक्स के साथ उत्पादन करता हूं क्योंकि मुझे उन्हें लिखने और बनाए रखने के लिए बेहतर तरीका मिलता है। जैसे ऊपरी कोड के बाद मेरे पास बाकी की तरह उत्पन्न होता है

cat << EOF | sudo tee -a /usr/local/bin/upgradeAllServers &> /dev/null
then
    # Print out ExitCode legend
    echo " ExitCode 42 - upgrade failed"
    echo " ExitCode 43 - Upgrade failed"
    echo " ExitCode 44 - Dist-Upgrade failed"
    echo " ExitCode 45 - Autoremove failed"
    echo ""
    echo ""
fi
EOF

तो अंतिम कोड ब्लॉक जैसा दिखता है

if (( ($server1_E != 0 && $server1_E != 1) || ($server2_E != 0 && $server2_E != 1) ))
then
    # Print out ExitCode legend
    echo " ExitCode 42 - upgrade failed"
    echo " ExitCode 43 - Upgrade failed"
    echo " ExitCode 44 - Dist-Upgrade failed"
    echo " ExitCode 45 - Autoremove failed"
    echo ""
    echo ""
fi

मेरा प्रश्न
क्या कोई तरीका है कि वंशानुगत व्यवहार echo -neबिना रेखा-चिन्ह के समान होता है?


1
यदि आपको sudoएक स्क्रिप्ट की आवश्यकता है तो आप इसे गलत कर रहे हैं: इसके बजाय पूरे स्क्रिप्ट को रूट के रूप में चलाएं!
मिठाई

1
नहीं, क्योंकि यह अन्य सामान भी कर रहा है जिसे मैं रूट
derHugo


जैसा मैं कर रहा हूं वैसा करने में क्या दिक्कत है?
derHugo

4
ठीक है, वहाँ एक समस्या है: sudoउपयोगकर्ता नाम के बिना एक स्क्रिप्ट पासवर्ड के लिए पूछता है, जब तक कि आप इसे टाइप नहीं करते हैं इसमें देरी है। यह और भी बदतर है यदि आप एक टर्मिनल में स्क्रिप्ट नहीं चलाते हैं, तो आप पासवर्ड क्वेरी भी नहीं देख सकते हैं और यह सिर्फ काम नहीं करेगा। sudo -uदृष्टिकोण इन समस्याओं के किसी भी जरूरत नहीं है।
मिठाई

जवाबों:


9

नहीं, वंशानुगत हमेशा एक नई रेखा में समाप्त होता है। लेकिन आप अभी भी अंतिम न्यूलाइन निकाल सकते हैं, उदाहरण के लिए पर्ल के साथ:

cat << 'EOF' | perl -pe 'chomp if eof'
First line
Second line
EOF
  • -pइनपुट लाइन को लाइन से पढ़ता है, निर्दिष्ट कोड चलाता है -eऔर (संभवतः संशोधित) लाइन प्रिंट करता है
  • अगर यह मौजूद है तो chomp अंतिम न्यूलाइन को हटा देता है, फ़ाइल के अंत में ईओएफ सही होता है।

1
@ यार अगर प्रति-अंत-फ़ाइल (इस मामले में बंद पाइप में) का सामना करना पड़ा, तो यह अंतिम पंक्ति (जो कि हेरेडोक और हेस्टिंग्रिंग को स्वचालित रूप से जोड़ते हैं) से नईलाइन चार को चकित कर देगा
सर्गी

7

क्या एक तरीका है एक वंशानुगत प्रतिध्वनि के बिना एक प्रतिध्वनि के समान व्यवहार करता है?

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

हालांकि, बैश-ओनली तरीकों के माध्यम से इसे अप्रोच करने का एक तरीका यह होगा कि स्टैंडर्ड while IFS= read -rविधि के माध्यम से हेरेडोक क्या देता है , लेकिन एक देरी जोड़ें और printfअनुवर्ती नई लाइन के बिना अंतिम पंक्ति प्रिंट करें । यहां केवल एक व्यक्ति केवल बैश कर सकता है:

#!/usr/bin/env bash

while true
do
    IFS= read -r line || { printf "%s" "$delayed";break;}
    if [ -n "$delayed" ]; 
    then
        printf "%s\n" "$delayed"
    fi
    delayed=$line
done <<EOF
one
two
EOF

आप जो देख रहे हैं वह सामान्य है, जबकि लूप IFS= read -r lineएप्रोच के साथ है, हालांकि प्रत्येक पंक्ति को एक चर में संग्रहित किया जाता है और इस तरह देरी हो जाती है (इसलिए हम पहली पंक्ति को प्रिंट करना छोड़ देते हैं, इसे स्टोर करते हैं, और केवल तब ही प्रिंट करना शुरू करते हैं जब हमने दूसरी पंक्ति पढ़ी होती है)। इस तरह हम अंतिम पंक्ति पर कब्जा कर सकते हैं, और जब अगली पुनरावृत्ति पर readबाहर निकलने की स्थिति 1 आती है, तो यह है कि जब हम नई लाइन को बिना लाइन के प्रिंट करते हैं printf। Verbose? हाँ। लेकिन यह काम करता है:

$ ./strip_heredoc_newline.sh                                      
one
two$ 

ध्यान दें कि $शीघ्र चरित्र को आगे बढ़ाया जाए, क्योंकि कोई नई रेखा नहीं है। एक बोनस के रूप में, यह समाधान पोर्टेबल और POSIX-ish है, इसलिए इसे kshऔर dashसाथ ही काम करना चाहिए ।

$ dash ./strip_heredoc_newline.sh                                 
one
two$

6

मैं आपको एक अलग दृष्टिकोण की कोशिश करने की सलाह देता हूं। एक साथ कई इको स्टेटमेंट और हेरेडोक्स से अपनी जेनरेट की गई स्क्रिप्ट को पाइक करने के बजाय। मेरा सुझाव है कि आप एकल हेरेडोक का उपयोग करने का प्रयास करें।

आप एक हेरेडोक के अंदर चर विस्तार और कमांड प्रतिस्थापन का उपयोग कर सकते हैं। इस उदाहरण में पसंद करें:

#!/bin/bash
cat <<EOF
$USER $(uname)
EOF

मुझे लगता है कि यह अक्सर उत्पादन टुकड़ा द्वारा उत्पादन टुकड़ा की तुलना में बहुत अधिक पठनीय अंत परिणाम की ओर जाता है।

इसके अलावा ऐसा लगता है कि आप #!अपनी स्क्रिप्ट की शुरुआत में लाइन भूल रहे हैं। #!लाइन किसी भी सही ढंग से प्रारूपित लिपियों में अनिवार्य है। #!लाइन के बिना स्क्रिप्ट चलाने का प्रयास केवल तभी काम करेगा जब आप इसे एक ऐसे शेल से कहेंगे जो बुरी तरह से स्वरूपित स्क्रिप्ट के आसपास काम करता है, और यहां तक ​​कि इस मामले में यह आपके द्वारा इच्छित उद्देश्य से एक अलग शेल द्वारा व्याख्या हो सकती है।


havent भूल गया, #!लेकिन मेरा कोड ब्लॉक 2000 लाइनों की स्क्रिप्ट में से सिर्फ एक स्निपेट है;) मुझे अभी नहीं दिखता है कि कैसे आपका सुझाव मेरी समस्या को हल करता है, जबकि थोड़ी देर में कोड की एक लाइन उत्पन्न करता है ...
derHugo

लाइन के उस भाग के लिए @derHugo कमांड प्रतिस्थापन जहां आपको लूप की आवश्यकता होती है, ऐसा करने का एक तरीका है। एक और तरीका है कि भाग को हेरेडोक से पहले एक चर में बनाया जाए। दोनों में से कौन सबसे अधिक पठनीय है यह लूप में आवश्यक कोड की लंबाई पर निर्भर करता है और साथ ही प्रश्न में लाइन से पहले आपके पास हेरेडोक की कितनी लाइनें हैं।
कास्परड

@derHugo कमांड प्रतिस्थापन एक स्क्रिप्ट में पहले से परिभाषित शेल फ़ंक्शन को लागू करना एक तीसरा दृष्टिकोण है जो कि एक पंक्ति बनाने के लिए महत्वपूर्ण मात्रा में कोड की आवश्यकता होने पर अधिक पठनीय हो सकता है।
कास्परड

@derHugo: ध्यान दें कि: (1) आपके पास एक लूप हो सकता है जो सभी आवश्यक कमांड को एक चर में रखता है; (2) आप $( ...command...)एक हेरेडोक के अंदर का उपयोग कर सकते हैं , उन बिंदुओं के आउटपुट को इनरेडोक में उस बिंदु पर सम्मिलित कर सकते हैं ; (३) बैश में एरे चर होते हैं, जिन्हें आप इनलाइन का विस्तार कर सकते हैं, और यदि आवश्यक हो तो प्रारंभ / अंत में चीजों को जोड़ने के लिए प्रतिस्थापन का उपयोग कर सकते हैं। साथ में ये कैस्पर के सुझाव को और अधिक शक्तिशाली बनाते हैं (और आपकी स्क्रिप्ट संभवतः अधिक पठनीय है)।
भजन

मैं उनके प्रकार के व्यवहार (wysiwyg) की वजह से heredocs का उपयोग कर रहा हूं। पूरे टेम्प्लेट को दूसरी जगह पर प्रोड्यूस करना और मेरी राय में इसे हेरेडोक तक पहुँचाने से वास्तव में चीजों को पढ़ने / बनाए रखने में आसानी नहीं होती है।
derHugo

2

Heredocs हमेशा एक नई-पंक्ति के वर्णों में समाप्त होती हैं, लेकिन आप बस इसे हटा सकते हैं। सबसे आसान तरीका मुझे पता है कि headकार्यक्रम के साथ है :

head -c -1 <<EOF | sudo tee file > /dev/null
my
heredoc
content
EOF

कूल मुझे नहीं पता था कि -cनकारात्मक मूल्य भी लेता है! उस pearlसमाधान
derHugo

1

आप अपनी पसंद के अनुसार नई कड़ियों को हटा सकते हैं, पाइपिंग trकरना शायद सबसे सरल होगा। यह निश्चित रूप से सभी नई सुर्खियों को हटा देगा।

$ tr -d '\n' <<EOF 
if ((
EOF

लेकिन, यदि आप जिस स्टेटमेंट का निर्माण कर रहे हैं, उसकी आवश्यकता नहीं है, तो अंकगणित की अभिव्यक्ति (( .. ))को ठीक काम करना चाहिए , भले ही इसमें न्यूलाइन्स शामिल हों।

तो, आप कर सकते हैं

cat <<EOF 
if ((
EOF
for name in x y; do 
    cat << EOF
    ( \$${name}_E != 0 && \$${name}_E != 1 ) ||
EOF
done
cat <<EOF
    0 )) ; then 
    echo do something
fi
EOF

उत्पादन

if ((
    ( $x_E != 0 && $x_E != 1 ) ||
    ( $y_E != 0 && $y_E != 1 ) ||
    0 )) ; then 
    echo do something
fi

लूप में इसका निर्माण अभी भी बदसूरत है, हालांकि। || 0कि हम विशेष मामले के लिए पहले या अंतिम लाइन की जरूरत नहीं है पाठ्यक्रम इसलिए की है।


इसके अलावा, आपके पास | sudo tee ...हर आउटपुट में है। मुझे लगता है कि हम केवल एक बार पुनर्निर्देशन (प्रक्रिया प्रतिस्थापन के साथ) खोलकर, और बाद में मुद्रण के लिए इसका उपयोग करके छुटकारा पा सकते हैं:

exec 3> >(sudo tee outputfile &>/dev/null)
echo output to the pipe like this >&3
echo etc. >&3
exec 3>&-         # close it in the end

और स्पष्ट रूप से, मुझे अभी भी लगता है कि बाहरी स्क्रिप्ट (जैसे कि \$${name}_E) में चर से चर नामों का निर्माण थोड़ा बदसूरत है, और इसे संभवतः एक साहचर्य सरणी के साथ बदल दिया जाना चाहिए ।

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