2009-08-20 6 views
57

मेरी लिपि में बैश में, बहुत सारे चर हैं, और मुझे उन्हें फ़ाइल में सहेजने के लिए कुछ करना है। मेरा प्रश्न सभी चर मेरी स्क्रिप्ट में घोषित सूची कैसे और इस तरह सूची प्राप्त है:स्क्रिप्ट में घोषित चरों को कैसे सूचीबद्ध करें?

VARIABLE1=abc 
VARIABLE2=def 
VARIABLE3=ghi 

उत्तर

102

set इच्छा आउटपुट चर, दुर्भाग्य से यह भी उत्पादन कार्यों के रूप में अच्छी तरह से परिभाषित करता है।

सौभाग्य से POSIX मोड केवल चर आउटपुट:

(set -o posix ; set) | less 

पाइपिंग के लिए less, या जहाँ आप विकल्प चाहते ले जाते हैं।

तो चर सिर्फ लिपि में घोषित करने के लिए:

(set -o posix ; set) >/tmp/variables.before 
source script 
(set -o posix ; set) >/tmp/variables.after 
diff /tmp/variables.before /tmp/variables.after 
rm /tmp/variables.before /tmp/variables.after 

(या कम से कम कुछ है कि :-) के आधार पर)

+0

जब आप पोस्ट कर रहे थे तो आपने संपादित किया था। '-o posix' के साथ अच्छी कॉल अब एक diff में केवल चर शामिल होंगे। – ezpz

+6

अस्थायी फ़ाइलों का उपयोग किए बिना: 'VARS = "\' set -o posix; सेट \ '"; स्रोत स्क्रिप्ट; SCRIPT_VARS = "\' grep -vFe "$ VARS" <<< "$ (सेट-पॉज़िक्स; सेट)" | grep -v^VARS = \ '"; VARS अनसेट; '। यह एक तैयार-से-सहेजने वाले प्रारूप में वर्रों को भी आउटपुट करेगा। सूची में स्क्रिप्ट बदलने वाले वेरिएबल्स शामिल होंगे (यह निर्भर करता है कि यह वांछनीय है) –

+0

दुर्भाग्यवश पॉज़िक्स मोड भी ऐसे वर्ट्स को आउटपुट करता है जो अनसेटटेबल हैं, इसलिए आप इसके आउटपुट को "स्रोत" नहीं कर सकते हैं और उन्हें वापस पढ़ सकते हैं। –

3

आपके द्वारा पोस्ट की प्रक्रिया कर सकते हैं, (पहले से ही उल्लेख किया) आप बस अपनी स्क्रिप्ट की शुरुआत और अंत में एक set कॉल कर सकते हैं (प्रत्येक एक अलग फ़ाइल में) और दो फाइलों पर एक अंतर करें। महसूस करें कि इसमें अभी भी कुछ शोर होगा।

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

store() { 
    export ${1}="${*:2}" 
    [[ ${STORED} =~ "(^|)${1}($|)" ]] || STORED="${STORED} ${1}" 
} 

store VAR1 abc 
store VAR2 bcd 
store VAR3 cde 

for i in ${STORED}; do 
    echo "${i}=${!i}" 
done 

पैदावार कौन सा

VAR1=abc 
VAR2=bcd 
VAR3=cde 
0

एक स्क्रिप्ट का उपयोग कर प्रयास करें के लिए (की सुविधा देता है यह कहते हैं "ls_vars"):

#!/bin/bash 
    set -a 
    env > /tmp/a 
    source $1 
    env > /tmp/b 
    diff /tmp/{a,b} | sed -ne 's/^> //p' 

chmod + x यह, और:

ls_vars your-script.sh > vars.files.save 
+2

यह स्थानीय चर, केवल निर्यात किए गए लोगों को नहीं दिखाता है। –

8
for i in _ {a..z} {A..Z}; do eval "echo \${[email protected]}" ; done | xargs printf "%s\n" 

यह सभी शैल चर नामों को मुद्रित करना होगा। आप अपनी फ़ाइल को सोर्स करने से पहले और बाद में एक सूची प्राप्त कर सकते हैं जैसे कि "सेट" के साथ भिन्नताएं भिन्न हैं (जैसा कि अन्य उत्तरों में बताया गया है)। लेकिन ध्यान रखें कि diff के साथ इस तरह के फ़िल्टरिंग को आपके द्वारा आवश्यक कुछ चर फ़िल्टर कर सकते हैं लेकिन आपकी फ़ाइल को सोर्स करने से पहले मौजूद थे।

आपके मामले में, अगर आप अपने चर के नाम पता है "चर" के साथ शुरू है, तो आप अपनी स्क्रिप्ट स्रोत कर सकते हैं और कार्य करें:

for var in ${[email protected]}; do 
    printf "%s%q\n" "$var=" "${!var}" 
done 

अद्यतन: शुद्ध मार समाधान के लिए (कोई बाहरी आदेशों का इस्तेमाल किया):

for i in _ {a..z} {A..Z}; do 
    for var in `eval echo "\\${[email protected]}"`; do 
     echo $var 
     # you can test if $var matches some criteria and put it in the file or ignore 
    done 
done 
27
compgen -v 

यह स्थानीय लोगों सहित सभी चर सूचीबद्ध करता है। मैंने इसे bash: get list of variables whose name matches a certain pattern से सीखा, और इसे my script में उपयोग किया।

+0

अफसोस की बात है, 'compgen -v' भी वैश्विक चर सूचीबद्ध करता है जो स्थानीय रूप से अनसेट थे। सुनिश्चित नहीं है कि यह एक लंबे समय से चलने वाली बग या वांछित व्यवहार है। –

0

एक सुरक्षा के दृष्टिकोण से, या तो @ akostadinov के answer या @ JuvenXu के answer निम्नलिखित संभावित सुरक्षा दोष के कारण, set कमान की असंरचित उत्पादन पर भरोसा करने के लिए बेहतर है:

#!/bin/bash 

function doLogic() 
{ 
    local COMMAND="${1}" 
    if (set -o posix; set | grep -q '^PS1=') 
    then 
     echo 'Script is interactive' 
    else 
     echo 'Script is NOT interactive' 
    fi 
} 

doLogic 'hello' # Script is NOT interactive 
doLogic $'\nPS1=' # Script is interactive 

ऊपर समारोह doLogic का उपयोग करता है set वैरिएबल PS1 की उपस्थिति की जांच करने के लिए यह निर्धारित करने के लिए कि क्या स्क्रिप्ट इंटरैक्टिव है या नहीं (कभी भी यह ध्यान न दें कि यह लक्ष्य पूरा करने का सबसे अच्छा तरीका है; यह सिर्फ एक उदाहरण है।)

हालांकि, set का उत्पादन असंगठित है, जिसका अर्थ है कि कोई भी चर जो एक नई रेखा है, पूरी तरह से परिणामों को दूषित कर सकती है।

यह निश्चित रूप से एक संभावित सुरक्षा जोखिम है। इसके बजाय, अप्रत्यक्ष परिवर्तनीय नाम विस्तार, या compgen -v के लिए या तो बैश के समर्थन का उपयोग करें।

-1

इस प्रयास करें: set | egrep "^\w+="

पहले प्रस्तावित समाधान, (set -o posix ; set) | less (के साथ या | less पाइपिंग के बिना), काम करता है लेकिन एक खामी है: यह टर्मिनल के लिए नियंत्रण कोड पहुंचाता है, ताकि वे ठीक से प्रदर्शित नहीं कर रहे हैं। उदाहरण के लिए, अगर वहाँ (संभावना) एक IFS=$' \t\n' चर, हम देख सकते हैं:

IFS=' 
' 

... बजाय।

मेरा egrep समाधान इस (और अंत में अन्य similars वाले) प्रदर्शित करता है ठीक से।

+0

यह 8 साल हो गया है, आपको पता है – lauriys

+0

** डाउनवॉटेड क्योंकि यह सादा गलत है ** 'bash -c $ 'a() {echo" \ nA = B "; }; एसेट ए; सेट | egrep "^ \ w + =" '| grep^ए' प्रदर्शित करता है 'ए = बी' '-> विफल! – Tino

0

मैं शायद the answer समय पहले चोरी किया है ... वैसे भी थोड़ा एक समारोह के रूप में विभिन्न:

## 
    # usage source bin/nps-bash-util-funcs 
    # doEchoVars 
    doEchoVars(){ 

     # if the tmp dir does not exist 
     test -z ${tmp_dir} && \ 
     export tmp_dir="$(cd "$(dirname $0)/../../.."; pwd)""/dat/log/.tmp.$$" && \ 
     mkdir -p "$tmp_dir" && \ 
     (set -o posix ; set)| sort >"$tmp_dir/.vars.before" 


     (set -o posix ; set) | sort >"$tmp_dir/.vars.after" 
     cmd="$(comm -3 $tmp_dir/.vars.before $tmp_dir/.vars.after | perl -ne 's#\s+##g;print "\n $_ "')" 
     echo -e "$cmd" 
    } 
3

ऊपर कुछ उत्तर के आधार पर, यह मेरे लिए काम किया:

before=$(set -o posix; set | sort); 

स्रोत फ़ाइल:

comm -13 <(printf %s "$before") <(set -o posix; set | sort | uniq) 
0

यहां ऐसा है @GinkgoFr जवाब देने के लिए इसी तरह की mething है, लेकिन समस्याओं @Tino या @DejayClayton, से पहचान और बिना @ DouglasLeeder के चतुर set -o posix बिट से अधिक मजबूत है:

+ function SOLUTION() { (set +o posix; set) | sed -ne '/^\w\+=/!q; p;'; } 

अंतर यह है कि इस समाधान पहली गैर के बाद बंद हो जाता है - उपलब्ध रिपोर्ट, उदाहरण के लिए set

बीटीडब्ल्यू द्वारा रिपोर्ट किया गया पहला फ़ंक्शन: "टिनो" समस्या हल हो गई है। हालांकि POSIX बंद है और फ़ंक्शन set, sed ... समाधान के हिस्से की रिपोर्ट केवल तभी रिपोर्ट करता है (उदा। VAR=VALUE लाइनें)। विशेष रूप से, A2 नकली रूप से आउटपुट में इसे बनाता है।

+ function a() { echo $'\nA2=B'; }; A0=000; A9=999; 
+ SOLUTION | grep '^A[0-9]=' 
A0=000 
A9=999 

और: "DejayClayton" समस्या हल हो जाता है (चर मान में एम्बेडेड नई-पंक्तियों नहीं उत्पादन को बाधित करते हैं - प्रत्येक VAR=VALUE एक भी उत्पादन लाइन प्राप्त):

+ A1=$'111\nA2=222'; A0=000; A9=999; 
+ SOLUTION | grep '^A[0-9]=' 
A0=000 
A1=$'111\nA2=222' 
A9=999 

नोट: समाधान @DouglasLeeder द्वारा प्रदान की गई "DejayClayton" समस्या (एम्बेडेड न्यूलाइन के साथ मूल्य) से पीड़ित है। नीचे, A1 गलत है और A2 बिल्कुल दिखाई नहीं देना चाहिए।

$ A1=$'111\nA2=222'; A0=000; A9=999; (set -o posix; set) | grep '^A[0-9]=' 
A0=000 
A1='111 
A2=222' 
A9=999 

अंत: मैं bash मामलों के संस्करण नहीं लगता कि है, लेकिन यह हो सकता है। मैं अपने परीक्षण किया था/इस पर विकासशील:

$ bash --version 
GNU bash, version 4.4.12(1)-release (x86_64-pc-msys) 

बाद स्क्रिप्ट: यह देखते हुए ओपी करने के लिए अन्य प्रतिक्रियाओं में से कुछ, मैं चला रहा हूँ < 100% यकीन है कि set हमेशा के लिए मूल्य के भीतर नई-पंक्तियों धर्मान्तरित \n, जो यह समाधान "DejayClayton" समस्या से बचने के लिए निर्भर करता है। शायद यह एक आधुनिक व्यवहार है? या एक संकलन समय भिन्नता? या set -o या shopt विकल्प सेटिंग? यदि आप इस तरह के बदलावों के बारे में जानते हैं, तो कृपया एक टिप्पणी जोड़ें ...

संबंधित मुद्दे