कैसे केवल परिभाषित चर (शेल और / या पर्यावरण चर) को बश में प्रिंट करें


57

बैश बिलियन कमांड set, यदि बिना तर्क के लागू किया जाता है, तो सभी शेल और पर्यावरण चर, लेकिन सभी परिभाषित कार्यों को भी प्रिंट करेगा। यह मनुष्यों के लिए उत्पादन को बेकार कर देता है और मुश्किल में डाल देता है grep

मैं बैश बिलियन कमांड setप्रिंट केवल चर कैसे बना सकता हूं और फ़ंक्शन नहीं कर सकता हूं ?

क्या अन्य कमांड हैं जो केवल शेल वेरिएबल्स को प्रिंट करते हैं, फ़ंक्शन के बिना?

नोट: गोले चर और पर्यावरण चर के बीच अंतर। यहां देखें बैश में पर्यावरण चर और निर्यात पर्यावरण चर के बीच अंतर

जवाबों:


51

"क्या अन्य कमांड हैं जो फ़ंक्शन के बिना केवल शेल वेरिएबल प्रिंट करता है?"

मैन बैश में, SHELL BUILTIN COMMANDS (सेट सेक्शन में) अनुभाग में कहा गया है: "पॉज़िक्स मोड में, केवल शेल वेरिएबल्स सूचीबद्ध हैं।"

(set -o posix; set)

ध्यान दें: ()सिंटैक्स एक उप-प्रकार को जन्म देता है, यदि आपको पसंद नहीं है तो केवल अधिक वर्बोज़ संस्करण का उपयोग करें

set -o posix; set; set +o posix

1
अब तक का सबसे अच्छा समाधान
रुस्लान

1
के साथ शुरू आमतौर पर नीरस चर का एक गुच्छा रहे हैं _:, जिनमें से छुटकारा पाने के लिए आसान कर रहे हैं(set -o posix ; set | grep -v ^_)
हाइड

यह मुझे बहुत समय से परेशान कर रहा है! यदि आपके पास बहु-पंक्ति मान हैं, तो _ के साथ शुरू होने वाली पंक्तियों को अलग करना पर्याप्त नहीं है, यह अभी भी चालों में मूल्य की सामग्री को छोड़ देगा। चूँकि सेट लाइनों को क्रम में प्रिंट करता है, सभी _ लाइनें अंत में होंगी, इसलिए आप पहले _ लाइन के बाद परिणाम काट सकते हैं, उपयोग कर सकते हैं:set -o posix; set | sed -e '/^_/,$d'; set +o posix;
स्कॉट

1
बस एक ध्यान दें: कोष्ठक महत्वपूर्ण हैं (set -o posix; set)। कोष्ठक के बिना वर्तमान बैश शेल का व्यवहार पॉज़िक्स मानक से मेल खाने के लिए बदला जाएगा। (डन्नो का मतलब क्या है लेकिन महत्वपूर्ण दिखता है।) कोष्ठक के साथ, बैश अपरिवर्तित रहता है।
जॉन रेड

1
साइड इफेक्ट्स : सेट POSIXLY_CORRECT=yऔर कहते posixहैं$SHELLOPTS
टॉम हेल

31

यहाँ कुछ काम कर रहे हैं:

$ comm -3 <(declare | sort) <(declare -f | sort)

टूट - फूट:

  1. declare प्रत्येक परिभाषित चर (निर्यात या नहीं) और फ़ंक्शन को प्रिंट करता है।
  2. declare -f प्रिंट केवल कार्य करता है।
  3. comm -3दोनों के लिए सभी लाइनों को आम हटा देगा। वास्तव में यह केवल चर को छोड़कर, कार्यों को हटा देगा।

केवल उन वेरिएबल्स को प्रिंट करने के लिए जिन्हें निर्यात नहीं किया जाता है:

$ comm -3 <(comm -3 <(declare | sort) <(declare -f | sort)) <(env | sort)

एक और समाधान:

$ declare -p

यह केवल चर को प्रिंट करेगा, लेकिन कुछ बदसूरत विशेषताओं के साथ।

declare -- BASH="/bin/bash"
declare -ir BASHPID=""
declare -A BASH_ALIASES='()'
declare -a BASH_ARGC='()'
...

आप विशेषताओं का उपयोग करके काट सकते हैं ... कट:

$ declare -p | cut -d " " -f 3

एक नकारात्मक पहलू यह है कि IFS का मूल्य प्रदर्शित होने के बजाय व्याख्या किया जाता है।

तुलना:

$ comm -3 <(declare | sort) <(declare -f | sort)
...
IFS=$' \t\n'
...
$ declare -p | cut -d " " -f 3
...
IFS="
"
...

यह उस उत्पादन को आगे की प्रक्रिया के लिए उपयोग करने में काफी कठिन बनाता है, क्योंकि यह "एक पंक्ति में अकेला है। इसे रोकने के लिए शायद कुछ IFS- फू किया जा सकता है।


अभी तक एक और समाधान, का उपयोग कर compgen:

$ compgen -v

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

मूल्यों को सूचीबद्ध करने के लिए यहां एक हैक भी है।

$ compgen -v | while read var; do printf "%s=%q\n" "$var" "${!var}"; done

लाभ: यह एक शुद्ध बैश समाधान है। नुकसान: कुछ मूल्यों की व्याख्या के कारण गड़बड़ हो जाती है printf। इसके अलावा पाइप और / या लूप से उपधारा कुछ अतिरिक्त चर जोड़ते हैं।


declare ...| cutयदि आपके चर के लिए कोई विशेषता नहीं है, तो क्या आपका पाइप टूट जाता है? मैं अनुमान लगा रहा हूं कि --उस मामले में इसका उपयोग किया जाता है, लेकिन मैं अभी भी असहज हूं। sedसुरक्षित हो सकता है, यानीdeclare -p | sed 's/^.* \([^ ]\+\)$/\1/'
jmtd

+1 के लिए compgen:)
RSFalcon7

13

typesetBuiltin अजीब केवल (कार्यों को दिखाने का विकल्प है -f), लेकिन न केवल मानकों को दिखाने के लिए। सौभाग्य से, typeset(या set) सभी फ़ंक्शंस से पहले सभी मापदंडों को प्रदर्शित करता है, फ़ंक्शन और पैरामीटर नाम में नईलाइन या समान संकेत नहीं हो सकते हैं, और पैरामीटर मानों में नई रूपरेखा उद्धृत की जाती हैं (वे जैसे दिखाई देते हैं \n)। तो आप पहली पंक्ति में रुक सकते हैं जिसमें समान चिह्न नहीं है:

set | awk -F '=' '! /^[0-9A-Z_a-z]+=/ {exit} {print $1}'

यह केवल पैरामीटर नामों को प्रिंट करता है; यदि आप मान चाहते हैं, तो बदल print $1दें print $0

ध्यान दें कि यह सभी पैरामीटर नाम (पैरामीटर और चर समानार्थी रूप से यहां उपयोग किए जाते हैं) प्रिंट करता है, न कि केवल पर्यावरण चर ("पर्यावरण चर" "निर्यात मापदंडों" का पर्याय है)।

यह भी ध्यान दें कि यह मानता है कि एक ऐसे नाम के साथ कोई पर्यावरण चर नहीं है जो पैरामीटर नामों पर बैश की बाधाओं से मेल नहीं खाता है। ऐसे वैरिएबल को बैश के अंदर नहीं बनाया जा सकता है, लेकिन बैश शुरू होने पर पर्यावरण से विरासत में मिला हो सकता है:

env 'foo ()
{
  =oops' bash

महान समाधान! मैंने पहली पंक्ति में रुकने के बारे में सोचा भी नहीं था जिसमें '=' ​​नहीं है। +1
स्टीवन डी

समान रूप से, sed के साथ: set | sed '/=/!Q'
Toby Speight

7

मैं अनिश्चित हूं कि कोई setप्रिंट को केवल चर कैसे बना सकता है । हालांकि, के उत्पादन को देखकर set, मैं निम्नलिखित के साथ आने में सक्षम था जो सिर्फ चर को हथियाने के लिए लगता है:

$ set | grep "^\([[:alnum:]]\|[[:punct:]]\)\+=" 

मूल रूप से, मैं उन पंक्तियों की तलाश कर रहा हूं जो अक्षरों, संख्याओं या विराम चिह्नों से शुरू होती हैं और उसके बाद "="। मेरे द्वारा देखे गए आउटपुट से, यह सभी चर को पकड़ लेता है; हालाँकि, मुझे संदेह है कि यह बहुत पोर्टेबल है।

यदि, जैसा कि आपका शीर्षक बताता है, आप इस सूची से निर्यात किए जाने वाले चर को घटाना चाहते हैं और इस प्रकार गैर-निर्यात किए गए चर की सूची प्राप्त कर सकते हैं, तो आप ऐसा कुछ कर सकते हैं

$ set | grep "^\([[:alnum:]]\|[[:punct:]]\)\+=" | sort > ./setvars && env | sort | comm -23 ./setvars - 

इसे थोड़ा तोड़ने के लिए, यहाँ यह है:

  1. set | grep "^\([[:alnum:]]\|[[:punct:]]\)\+=" | sort > ./setvars : यह उम्मीद है कि चर के सभी (जैसा कि पहले चर्चा की गई है), उन्हें सॉर्ट करें, और परिणाम को एक फ़ाइल में चिपका देता है।
  2. && env | sort: पिछली कमांड पूरी होने के बाद, हम envइसके आउटपुट को कॉल और सॉर्ट करने जा रहे हैं ।
  3. | comm -23 ./setvars -: अंत में, हम सॉर्ट किए गए आउटपुट को पाइप envकरते हैं commऔर -23पहले तर्क के लिए अद्वितीय लाइनों को प्रिंट करने के लिए विकल्प का उपयोग करते हैं, इस मामले में सेट से हमारे आउटपुट के लिए अद्वितीय लाइनें हैं।

जब आप हो जाते हैं तो आप अस्थायी फ़ाइल को साफ़ करना चाहते हैं जिसे उसने कमांड के साथ बनाया है rm ./setvars


आपके आदेश के साथ समस्या पोर्टेबिलिटी नहीं है (यह bash के लिए विशिष्ट है, निश्चित रूप से, लेकिन grep पक्ष में कोई समस्या नहीं है)। समस्या यह है कि आप फ़ंक्शन परिभाषाओं में कुछ पंक्तियाँ पकड़ रहे हैं। बैश अधिकांश फ़ंक्शन कोड का संकेत देता है, लेकिन यह सब नहीं, विशेष रूप से यहां दस्तावेजों के अंदर पाठ नहीं ( f () {|cat <<EOF|foo=bar|EOF|}जहां |एक लाइन ब्रेक का प्रतिनिधित्व करता है)।
गिल्स एसओ- बुराई को रोकें '26

6

बस कमांड का उपयोग करें env। यह कार्यों को प्रिंट नहीं करता है।


1
यह एक स्क्रिप्ट के अंदर इस्तेमाल किया जाता है।
DocSalvager

2

आदेश को प्रिंट करें:

$printenv

6
Printenv और env केवल प्रिंट एक्सपोर्टेड (एनवायरनमेंट) वैरिएबल और नॉन-एक्सपोर्टेड (शेल) वैरिएबल हैं।
लारी

@ श्री धन्यवाद! मुझे आश्चर्य है कि सिर्फ निर्यात किए गए चर को कैसे प्रिंट किया जाए।
मार्क स्टीवर्ट

1

बैश में, यह केवल चर नाम प्रिंट करेगा:

compgen -v

या, यदि मान भी आवश्यक हैं, तो उपयोग करें:

declare -p

आपके प्रयास के लिए धन्यवाद। कृपया ध्यान दें कि मैंने पहले ही अपने उत्तर unix.stackexchange.com/a/5691/1170 में उस संभावना का उल्लेख कर दिया है।
lesmana

0

एक साफ खोल के खिलाफ अलग करने के लिए यह सुनिश्चित करने के लिए कि आरसी स्क्रिप्ट्स से वेरिएशन को छोड़ दिया जाए

## get mostly local vars
diff_env(){
    diff <(bash -cl 'set -o posix && set') \
        <(set -o posix && set && set +o posix) | \
        grep -E "^>|^\+" | \
        grep -Ev "^(>|\+|\+\+) ?(BASH|COLUMNS|LINES|HIST|PPID|SHLVL|PS(1|2)|SHELL|FUNC)" | \
        sed -r 's/^> ?|^\+ ?//'
}

के साथ संस्करण commबहुत जटिल होगा


0

स्वीकृत उत्तर महान है। मैं एक विकल्प दे रहा हूं जिसमें POSIX मोड सेट करना शामिल नहीं है:

यहाँ मैं एक फाइल में फंक्शन स्टेट स्टोर करने के लिए जिस तकनीक का उपयोग कर रहा हूँ, उसे बाद में जारी रख सकता हूँ। पहला एक राज्य डंप का उत्पादन करता है और दूसरा केवल चर नामों की एक सूची तैयार करता है।

set 2>/dev/null | while read a; do [[ $a == *=* ]] || break; echo $a; done 

set 2>/dev/null | while read a; do [[ $a == *=* ]] || break; echo ${a/=*}; done 

दोनों तब तक डंपिंग लाइनों द्वारा काम करते हैं जब तक कि यह एक '=' चार के बिना नहीं मिलता है, जो तब होता है जब पहला फ़ंक्शन सूचीबद्ध होता है। बाद वाली फसलों का काम बंद हो गया।

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