बैश या ज़श में शेल वेरिएबल को सीरीज़ करें


12

क्या शेल चर को क्रमबद्ध करने का कोई तरीका है? मान लीजिए कि मेरे पास एक चर है $VAR, और मैं इसे एक फ़ाइल या जो कुछ भी सहेजना चाहता हूं, और फिर उसी मूल्य को वापस पाने के लिए इसे बाद में पढ़ सकता हूं?

क्या ऐसा करने का एक पोर्टेबल तरीका है? (मुझे ऐसा नहीं लगता)

क्या इसे बैश या ज़श में करने का कोई तरीका है?


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

^ कैलेब की उत्कृष्ट नागरिकता का एक और ^ उदाहरण।
मिकसेर

जवाबों:


14

चेतावनी: इनमें से किसी भी समाधान के साथ, आपको यह जानने की आवश्यकता है कि आप सुरक्षित होने के लिए डेटा फ़ाइलों की अखंडता पर भरोसा कर रहे हैं क्योंकि वे आपकी स्क्रिप्ट में शेल कोड के रूप में निष्पादित होंगे। उन्हें सुरक्षित करना आपकी स्क्रिप्ट की सुरक्षा के लिए सर्वोपरि है!

एक या अधिक चरों को क्रमबद्ध करने के लिए सरल इनलाइन कार्यान्वयन

हां, बाश और zsh दोनों में, आप एक चर की सामग्री को इस तरह से अनुक्रमित कर सकते हैं जो बिलिन typesetऔर -pतर्क का उपयोग करके पुनः प्राप्त करना आसान है । आउटपुट स्वरूप ऐसा है कि आप केवल sourceअपना सामान वापस पाने के लिए आउटपुट कर सकते हैं।

 # You have variable(s) $FOO and $BAR already with your stuff
 typeset -p FOO BAR > ./serialized_data.sh

आप अपना सामान इस तरह से बाद में अपनी स्क्रिप्ट में या किसी अन्य स्क्रिप्ट में पूरी तरह से वापस पा सकते हैं:

# Load up the serialized data back into the current shell
source serialized_data.sh

यह बैश, zsh और ksh के लिए काम करेगा जिसमें विभिन्न गोले के बीच डेटा पास करना शामिल है। बाश इसे अपने declareबिल्टइन फंक्शन में ट्रांसलेट करेगा जबकि zsh इसके साथ इम्प्लीमेंट करता है typesetलेकिन बैश के पास इस बात के लिए एक उपनाम है कि हम typesetksh कम्पैटिबिलिटी के लिए यहां इस्तेमाल करें।

कार्यों का उपयोग करके अधिक जटिल सामान्यीकृत कार्यान्वयन

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

इन सभी के लिए ध्यान दें, बैश / zsh क्रॉस-अनुकूलता बनाए रखने के लिए हम दोनों मामलों को ठीक कर रहे होंगे typesetऔर declareइसलिए कोड को दोनों या दोनों गोले में काम करना चाहिए। यह कुछ बल्क और मेस जोड़ता है, जिन्हें यदि आप केवल एक शेल या दूसरे के लिए कर रहे हैं, तो इसे समाप्त किया जा सकता है।

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

यह कई हैक्स में से एक के साथ तय किया जा सकता है। इसे ठीक करने का मेरा प्रारंभिक प्रयास ध्वज sedको जोड़ने के माध्यम से क्रमबद्ध प्रक्रिया के उत्पादन को पार्स करने के लिए था, -gइसलिए बनाया गया कोड वैश्विक वैरिएबल को परिभाषित करता है, जब इसे वापस भेजा जाता है।

serialize() {
    typeset -p "$1" | sed -E '0,/^(typeset|declare)/{s/ / -g /}' > "./serialized_$1.sh"
}
deserialize() {
    source "./serialized_$1.sh"
}

ध्यान दें कि कायरता sedअभिव्यक्ति केवल 'टाइपसेट' या 'घोषित' की पहली घटना से मेल खाना है और -gपहले तर्क के रूप में जोड़ना है। यह केवल पहली घटना से मेल खाने के लिए आवश्यक है क्योंकि, स्टीफन चेज़ेलस ने ठीक ही टिप्पणियों में बताया है, अन्यथा यह उन मामलों से भी मेल खाएगा जहां धारावाहिक रूप से स्ट्रिंग में शाब्दिक नए शब्द शामिल हैं, जिसके बाद शब्द घोषित या टाइपसेट होता है।

मेरे प्रारंभिक पार्सिंग फ़ॉक्स पेस को ठीक करने के अलावा , स्टीफ़ेन ने इसे हैक करने के लिए एक कम भंगुर तरीका भी सुझाया , जो न केवल साइड को स्ट्रिंग्स को पार्स करने के साथ मुद्दों को उठाता है, बल्कि क्रियाओं को फिर से परिभाषित करने के लिए रैपर फ़ंक्शन का उपयोग करके अतिरिक्त कार्यक्षमता जोड़ने के लिए एक उपयोगी हुक हो सकता है। जब डेटा वापस सोर्सिंग में लिया जाता है। यह मान लेता है कि आप घोषित या टाइपसेट कमांड के साथ कोई अन्य गेम नहीं खेल रहे हैं, लेकिन इस तकनीक को ऐसी स्थिति में लागू करना आसान होगा जहां आप इस कार्यक्षमता को अपने स्वयं के किसी अन्य फ़ंक्शन के हिस्से के रूप में शामिल कर रहे थे। आप लिखे गए डेटा के नियंत्रण में नहीं थे और इसमें -gध्वज जोड़ा गया था या नहीं । कुछ ऐसा ही उपनामों के साथ भी किया जा सकता है, कार्यान्वयन के लिए गिल्स का जवाब देखें ।

परिणाम को और अधिक उपयोगी बनाने के लिए, हम यह मानकर कि हमारे शब्द तर्क सरणी में प्रत्येक शब्द एक चर नाम है, कई कार्यों पर पारित कर सकते हैं। परिणाम कुछ इस तरह हो जाता है:

serialize() {
    for var in $@; do
        typeset -p "$var" > "./serialized_$var.sh"
    done
}

deserialize() {
    declare() { builtin declare -g "$@"; }
    typeset() { builtin typeset -g "$@"; }
    for var in $@; do
        source "./serialized_$var.sh"
    done
    unset -f declare typeset
}

या तो समाधान के साथ, उपयोग इस तरह दिखेगा:

# Load some test data into variables
FOO=(an array or something)
BAR=$(uptime)

# Save it out to our serialized data files
serialize FOO BAR

# For testing purposes unset the variables to we know if it worked
unset FOO BAR

# Load  the data back in from out data files
deserialize FOO BAR

echo "FOO: $FOO\nBAR: $BAR"

declareहै bashके बराबर kshकी typesetbash, उस संबंध में zshभी समर्थन typeset, typesetअधिक पोर्टेबल है। export -pPOSIX है, लेकिन यह कोई तर्क नहीं लेता है और इसका आउटपुट शेल डिपेंडेंट है (हालांकि यह POSIX गोले के लिए अच्छी तरह से निर्दिष्ट है, इसलिए उदाहरण के लिए जब bash या ksh को कहा जाता है sh)। अपने चर को उद्धृत करना याद रखें; यहाँ विभाजन + ग्लोब ऑपरेटर का उपयोग करने का कोई मतलब नहीं है।
स्टीफन चेज़लस

ध्यान दें जो -Eकेवल कुछ बीएसडी में पाया जाता है sed। परिवर्तनीय मूल्यों में न्यूलाइन वर्ण हो सकते हैं, इसलिए sed 's/^.../.../'सही तरीके से काम करने की गारंटी नहीं है।
स्टीफन चेजलस

यही वह है जिसकी तलाश में मैं हूं! मैं गोले के बीच चर को आगे-पीछे करने के लिए एक सुविधाजनक तरीका चाहता था।
fwenom

मेरा मतलब था: a=$'foo\ndeclare bar' bash -c 'declare -p a'स्थापित करने के लिए एक लाइन के साथ शुरू होता है कि उत्पादन होगा declare। शायद declare() { builtin declare -g "$@"; }कॉल करने से पहले करना बेहतर है source(और बाद में
परेशान

2
@ गिल्स, अलायस फ़ंक्शंस के अंदर काम नहीं करेगा (फ़ंक्शन परिभाषा के समय परिभाषित करने की आवश्यकता है), और बैश के साथ इसका मतलब है कि आपको shopt -s expandaliasइंटरेक्टिव नहीं होने की आवश्यकता होगी । फ़ंक्शंस के साथ, आप declareरैपर को भी बढ़ा सकते हैं ताकि यह केवल आपके द्वारा निर्दिष्ट चर को पुनर्स्थापित कर सके।
स्टीफन चेज़लस

3

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

#!/bin/bash
echo "$var"x > file
unset var
var="$(< file)"
var=${var%x}

वह शायद चर नाम को भी फ़ाइल में सहेजना चाहता है।
user80551

2

सभी को सीरियल करें - POSIX

किसी भी POSIX शेल में, आप सभी पर्यावरण चर को अनुक्रमित कर सकते हैं export -p। इसमें गैर-निर्यात शेल चर शामिल नहीं हैं। आउटपुट को ठीक से उद्धृत किया गया है ताकि आप इसे उसी शेल में वापस पढ़ सकें और बिल्कुल समान वैरिएबल मान प्राप्त कर सकें। आउटपुट किसी अन्य शेल में पठनीय नहीं हो सकता है, उदाहरण के लिए ksh नॉन-पोसिक्स $'…'सिंटैक्स का उपयोग करता है ।

save_environment () {
  export -p >my_environment
}
restore_environment () {
  . ./my_environment
}

कुछ या सभी को क्रमबद्ध करें - ksh, bash, zsh

Ksh (pdksh / mksh और ATT ksh दोनों), bash और zsh, बिल्डिन के साथ एक बेहतर सुविधा प्रदान करते हैं typesettypeset -pसभी परिभाषित चर और उनके मूल्यों को प्रिंट करता है (zsh उन चर के मूल्यों को छोड़ देता है जिन्हें साथ छिपा दिया गया है typeset -H)। आउटपुट में उचित घोषणा होती है, ताकि पर्यावरण चर का निर्यात वापस पढ़ने पर किया जाए (लेकिन अगर चर को पहले ही पढ़ते समय निर्यात किया जाता है, तो यह अस्पष्टीकृत नहीं होगा), ताकि सरणियों को सरणियों के रूप में वापस पढ़ा जाए, आदि। यहां भी, आउटपुट ठीक से उद्धृत किया गया है लेकिन केवल उसी शेल में पठनीय होने की गारंटी है। आप कमांड लाइन पर अनुक्रमित करने के लिए चर का एक सेट पास कर सकते हैं; यदि आप किसी भी चर को पास नहीं करते हैं तो सभी क्रमबद्ध हैं।

save_some_variables () {
  typeset -p VAR OTHER_VAR >some_vars
}

बाश और zsh में, एक फ़ंक्शन से पुनर्स्थापित नहीं किया जा सकता क्योंकि typesetकिसी फ़ंक्शन के अंदर स्टेटमेंट्स को उस फ़ंक्शन के लिए स्कोप किया जाता है। आपको . ./some_varsउस संदर्भ में चलने की आवश्यकता है जहां आप चर के मूल्यों का उपयोग करना चाहते हैं, इस बात का ख्याल रखते हुए कि निर्यात किए जाने वाले चर वैश्विक थे, जिन्हें वैश्विक के रूप में पुन: घोषित किया जाएगा। यदि आप किसी फ़ंक्शन के भीतर मान पढ़ना चाहते हैं और उन्हें निर्यात करना चाहते हैं, तो आप एक अस्थायी उपनाम या फ़ंक्शन की घोषणा कर सकते हैं। Zsh में:

restore_and_make_all_global () {
  alias typeset='typeset -g'
  . ./some_vars
  unalias typeset
}

बैश में (जिसके declareबजाय उपयोग होता है typeset):

restore_and_make_all_global () {
  alias declare='declare -g'
  shopt -s expand_aliases
  . ./some_vars
  unalias declare
}

Ksh में, typesetस्थानीय चर के साथ परिभाषित कार्यों में function function_name { … }और वैश्विक चर को परिभाषित कार्यों में घोषित करता है function_name () { … }

कुछ को सीरीज़ करें - POSIX

यदि आप अधिक नियंत्रण चाहते हैं, तो आप किसी चर की सामग्री को मैन्युअल रूप से निर्यात कर सकते हैं। चर की सामग्री को एक फ़ाइल में प्रिंट करने के लिए, printfबिलिन का उपयोग करें ( echoकुछ विशेष मामलों जैसे echo -nकुछ गोले पर और एक नई पंक्ति जोड़ता है):

printf %s "$VAR" >VAR.content

आप इस के साथ वापस पढ़ सकते हैं $(cat VAR.content), सिवाय इसके कि कमांड प्रतिस्थापन स्ट्रिपिंग नईलाइन्स को पीछे छोड़ देता है। इस शिकन से बचने के लिए, आउटपुट को कभी भी एक नई पंक्ति के साथ समाप्त न करने की व्यवस्था करें।

VAR=$(cat VAR.content && echo a)
if [ $? -ne 0 ]; then echo 1>&2 "Error reading back VAR"; exit 2; fi
VAR=${VAR%?}

यदि आप कई चर प्रिंट करना चाहते हैं, तो आप उन्हें एकल उद्धरणों के साथ उद्धृत कर सकते हैं, और सभी एम्बेडेड एकल उद्धरणों को बदल सकते हैं '\''। उद्धृत करने के इस रूप को किसी भी बॉर्न / POSIX- शैली शेल में वापस पढ़ा जा सकता है। निम्नलिखित स्निपेट किसी भी POSIX शेल में काम करता है। यह केवल स्ट्रिंग चर के लिए काम करता है (और उनके पास मौजूद गोले में संख्यात्मक चर, हालांकि उन्हें स्ट्रिंग के रूप में वापस पढ़ा जाएगा), यह गोले में सरणी चर से निपटने की कोशिश नहीं करता है जो उनके पास है।

serialize_variables () {
  for __serialize_variables_x do
    eval "printf $__serialize_variables_x=\\'%s\\'\\\\n \"\$${__serialize_variables_x}\"" |
    sed -e "s/'/'\\\\''/g" -e '1 s/=.../=/' -e '$ s/...$//'
  done
}

यहां एक और दृष्टिकोण है जो एक उपप्रकार को कांटा नहीं करता है, लेकिन स्ट्रिंग हेरफेर पर भारी है।

serialize_variables () {
  for __serialize_variables_var do
    eval "__serialize_variables_tail=\${$__serialize_variables_var}"
    while __serialize_variables_quoted="$__serialize_variables_quoted${__serialize_variables_tail%%\'*}"
          [ "${__serialize_variables_tail%%\'*}" != "$__serialize_variables_tail" ]; do
      __serialize_variables_tail="${__serialize_variables_tail#*\'}"
      __serialize_variables_quoted="${__serialize_variables_quoted}'\\''"
    done
    printf "$__serialize_variables_var='%s'\n" "$__serialize_variables_quoted"
  done
}

ध्यान दें कि शेल पर जो केवल-पढ़ने योग्य चर की अनुमति देते हैं, आपको एक त्रुटि मिलेगी यदि आप एक चर को पढ़ने की कोशिश करते हैं जो केवल-पढ़ने के लिए है।


इस तरह के रूप में चर में लाता है $PWDऔर $_- नीचे अपनी खुद की टिप्पणी देखें।
मिकसेर

@ कालेब कैसे के लिए typesetएक उपनाम बनाने के बारे में typeset -g?
गिलेस एसओ- बुराई को रोकना '

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

0

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

यह तकनीक इनपुट (विपरीत declare -a/ declare -p) को शेल-पार्स नहीं करती है और इसलिए धारावाहिक पाठ में मेटाचैटर्स के दुर्भावनापूर्ण सम्मिलन के खिलाफ सुरक्षित है।

नोट: नई सूचियों से बच नहीं रहे हैं, क्योंकि चरित्र जोड़ी readको हटा दिया जाता है \<newlines>, इसलिए -d ...इसे पढ़ने के लिए पारित किया जाना चाहिए, और फिर बिना पढ़े नए समाचारों को संरक्षित किया जाना चाहिए।

यह सब unserialiseफंक्शन में मैनेज होता है।

दो जादू पात्रों का उपयोग किया जाता है, क्षेत्र विभाजक और रिकॉर्ड विभाजक (ताकि एक ही स्ट्रीम में कई सरणियों को क्रमबद्ध किया जा सके)।

ये अक्षर के रूप में परिभाषित किया जा सकता है FSऔर RSलेकिन न तो के रूप में परिभाषित किया जा सकता है newlineक्योंकि एक भाग निकले न्यू लाइन द्वारा हटा दिया जाता है चरित्र read

एस्केप कैरेक्टर \बैकस्लैश होना चाहिए , जैसा कि readकैरेक्टर से पहचाने जाने वाले कैरेक्टर से बचने के लिए इस्तेमाल किया जाता है IFS

serialiseक्रमबद्ध "$@"करने के लिए क्रमबद्ध करेगा , serialise_toनामांकित संस्करण में क्रमबद्ध करेगा$1

serialise() {
  set -- "${@//\\/\\\\}" # \
  set -- "${@//${FS:-;}/\\${FS:-;}}" # ; - our field separator
  set -- "${@//${RS:-:}/\\${RS:-:}}" # ; - our record separator
  local IFS="${FS:-;}"
  printf ${SERIALIZE_TARGET:+-v"$SERIALIZE_TARGET"} "%s" "$*${RS:-:}"
}
serialise_to() {
  SERIALIZE_TARGET="$1" serialise "${@:2}"
}
unserialise() {
  local IFS="${FS:-;}"
  if test -n "$2"
  then read -d "${RS:-:}" -a "$1" <<<"${*:2}"
  else read -d "${RS:-:}" -a "$1"
  fi
}

और इसके साथ

unserialise data # read from stdin

या

unserialise data "$serialised_data" # from args

जैसे

$ serialise "Now is the time" "For all good men" "To drink \$drink" "At the \`party\`" $'Party\tParty\tParty'
Now is the time;For all good men;To drink $drink;At the `party`;Party   Party   Party:

(अनुगामी न्यूलाइन के बिना)

इसे वापस पढ़ें:

$ serialise_to s "Now is the time" "For all good men" "To drink \$drink" "At the \`party\`" $'Party\tParty\tParty'
$ unserialise array "$s"
$ echo "${array[@]/#/$'\n'}"

Now is the time 
For all good men 
To drink $drink 
At the `party` 
Party   Party   Party

या

unserialise array # read from stdin

बैश readने भागने वाले चरित्र का सम्मान किया \(जब तक कि आप -r ध्वज को पारित नहीं करते हैं) इनपुट फ़ील्ड पृथक्करण या लाइन परिसीमन जैसे वर्णों के विशेष अर्थ को हटाने के लिए।

यदि आप एक मात्र तर्क सूची के बजाय किसी सरणी को क्रमबद्ध करना चाहते हैं तो अपने सरणी को तर्क सूची के रूप में पास करें:

serialise_array "${my_array[@]}"

आप अपने unserialiseजैसे एक लूप में उपयोग कर सकते हैं readक्योंकि यह सिर्फ एक लिपटे पढ़ा है - लेकिन याद रखें कि धारा नईलाइन अलग नहीं है:

while unserialise array
do ...
done

यह तब काम नहीं करता है जब तत्वों में गैर-मुद्रण योग्य (वर्तमान स्थान में) हो या तब के रूप में TAB या newline जैसे वर्णों को नियंत्रित करता है bashऔर zshजैसा कि प्रस्तुत करता है $'\xxx'। के साथ bash -c $'printf "%q\n" "\t"'या प्रयास करेंbash -c $'printf "%q\n" "\u0378"'
स्टीफन चेज़लस

डार टॉटिन, तुम सही हो! मैं अपने उत्तर को प्रिंटफ% q का उपयोग न करने के लिए संशोधित करूंगा, लेकिन $ {@ // .. / ..} के बजाय सफेद स्थान से बचने के लिए पुनरावृत्तियों
सैम Liddicott

यह समाधान $IFSअनमॉडिफाइड होने पर निर्भर करता है और अब खाली सरणी तत्वों को ठीक से बहाल करने में विफल रहता है। वास्तव में, यह आईएफएस के एक अलग मूल्य का उपयोग करने के लिए अधिक समझ में आता है, और -d ''न्यूलाइन से बचने के लिए उपयोग करने से बचें। उदाहरण के लिए, :फ़ील्ड विभाजक के रूप में उपयोग करें और केवल उस और बैकस्लैश से बचने और IFS=: read -ad '' arrayआयात करने के लिए उपयोग करें।
स्टीफन चेज़लस

हाँ .... मैं पढ़ने में एक क्षेत्र विभाजक के रूप में इस्तेमाल किए जाने पर सफेद-अंतरिक्ष के विशेष उपचार के बारे में भूल गया। मुझे खुशी है कि आप आज गेंद पर हैं! आप \ n से बचने के लिए -d "" के बारे में सही हैं, लेकिन मेरे मामले में मैं धारावाहिकों की एक धारा पढ़ना चाहता था - हालांकि मैं उत्तर को अनुकूलित करूंगा। धन्यवाद!
सैम लिडिकोट

बच निकलने वाली न्यूलाइन इसे संरक्षित करने की अनुमति नहीं देती है, यह इसे एक बार चली जाती है read। बैकस्लैश-न्यूलाइन readएक और भौतिक रेखा पर एक तार्किक रेखा को जारी रखने का एक तरीका है। संपादित करें: आह मैं देख रहा हूँ कि आप पहले से ही newline के साथ समस्या का उल्लेख करते हैं।
स्टीफन चेजेलस

0

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

$ VAR="1/ 
,x"
$ echo "$VAR" | base64 > f
$ VAR=$(cat f | base64 -d)
$ echo "${VAR}X"
1/ 
,xX

-2
printf 'VAR=$(cat <<\'$$VAR$$'\n%s\n'$$VAR$$'\n)' "$VAR" >./VAR.file

ऐसा करने का एक और तरीका यह है कि आप 'इस तरह से सभी हार्डकॉट्स को संभालना सुनिश्चित करें:

sed '"s/'"'/&"&"&/g;H;1h;$!d;g;'"s/.*/VAR='&'/" <<$$VAR$$ >./VAR.file
$VAR
$$VAR$$

या साथ export:

env - "VAR=$VAR" sh -c 'export -p' >./VAR.file 

किसी भी POSIX शेल में पहला और दूसरा विकल्प काम करते हैं, यह मानते हुए कि चर के मान में स्ट्रिंग नहीं है:

"\n${CURRENT_SHELLS_PID}VAR${CURRENT_SHELLS_PID}\n" 

तीसरा विकल्प किसी भी POSIX खोल के लिए काम करना चाहिए लेकिन इस तरह के रूप में अन्य चर निर्धारित करने का प्रयास कर सकते _हैं या PWD। हालाँकि, सच्चाई यह है कि एकमात्र चर जिसे वह परिभाषित करने का प्रयास कर सकता है, उसे शेल द्वारा निर्धारित और बनाए रखा जाता है - और इसलिए भले ही आप exportउनमें से किसी एक के लिए आयात का मूल्य रखते हों - जैसे $PWDकि उदाहरण के लिए - शेल बस उन्हें फिर से सेट करेगा। वैसे भी सही मूल्य - कोशिश करो PWD=any_valueऔर अपने आप को देखने के लिए।

और क्योंकि - कम से कम जीएनयू के साथ bash- डिबग आउटपुट शेल में फिर से इनपुट के लिए स्वचालित रूप से सुरक्षित-उद्धृत है, यह 'हार्ड-कोट्स की संख्या की परवाह किए बिना काम करता है "$VAR":

 PS4= VAR=$VAR sh -cx 'VAR=$VAR' 2>./VAR.file

$VAR बाद में किसी भी स्क्रिप्ट में सहेजे गए मान पर सेट किया जा सकता है जिसमें निम्न पथ निम्न के साथ मान्य है:

. ./VAR.file

मुझे यकीन नहीं है कि आपने पहले कमांड में क्या लिखने की कोशिश की थी। $$रनिंग शेल का पीआईडी ​​है, क्या आपने उद्धरण गलत और माध्य \$या कुछ और प्राप्त किया है? यहां एक दस्तावेज़ का उपयोग करने का मूल तरीका काम किया जा सकता है, लेकिन यह मुश्किल है, एक-लाइनर सामग्री नहीं है: जो भी आप अंतिम मार्कर के रूप में चुनते हैं, आपको कुछ ऐसा चुनना होगा जो स्ट्रिंग में प्रकट नहीं होता है।
गिल्स एसओ- बुराई को रोकें '

दूसरा आदेश काम नहीं करता है जब $VARहोता है %। तीसरा कमांड हमेशा कई लाइनों वाले मानों के साथ काम नहीं करता है (यहां तक ​​कि स्पष्ट रूप से लापता दोहरे उद्धरण जोड़ने के बाद भी)।
गिल्स एसओ- बुराई को रोकना '

@ गिल्स - मुझे इसका पता है - मैं इसे एक अनूठे सीमांकक की स्थापना के एक सरल स्रोत के रूप में इस्तेमाल करता हूं। "हमेशा नहीं" से आपका क्या मतलब है? और मुझे समझ नहीं आ रहा है कि कौन से दोहरे उद्धरण गायब हैं - वे सभी परिवर्तनशील असाइनमेंट हैं। दोहरे उद्धरण केवल उस संदर्भ में स्थिति को भ्रमित करते हैं।
23 अक्टूबर को सुबह

@ गिल्स - मैं असाइनमेंट चीज़ को वापस लेता हूं - यह एक तर्क है env। मैं अभी भी उत्सुक हूं कि आपके पास कई लाइनों के बारे में क्या मतलब है - आखिरी sedतक मुठभेड़ VAR=तक हर पंक्ति को हटा देता है - इसलिए सभी लाइनें $VARपास हो जाती हैं। क्या आप कृपया एक उदाहरण प्रदान कर सकते हैं जो इसे तोड़ता है?
मोकेसर

आह, क्षमायाचना, तीसरी विधि काम करती है (उद्धरण सुधार के साथ)। खैर, (यहाँ चर नाम मानते हुए VAR) बदला नहीं है PWDया _शायद दूसरों है कि कुछ गोले परिभाषित या। दूसरी विधि में बैश की आवश्यकता होती है; से आउटपुट स्वरूप -vमानकीकृत नहीं है (डैश, ksh93, mksh और zsh काम में से कोई भी)।
गिल्स एसओ- बुराई को रोकें '

-2

लगभग समान लेकिन थोड़ा अलग:

अपनी स्क्रिप्ट से:

#!/usr/bin/ksh 

save_var()
{

    (for ITEM in $*
    do
        LVALUE='${'${ITEM}'}'
        eval RVALUE="$LVALUE"
        echo "$ITEM=\"$RVALUE\""  
    done) >> $cfg_file
}

restore_vars()
{
    . $cfg_file
}

cfg_file=config_file
MY_VAR1="Test value 1"
MY_VAR2="Test 
value 2"

save_var MY_VAR1 MY_VAR2
MY_VAR1=""
MY_VAR2=""

restore_vars 

echo "$MY_VAR1"
echo "$MY_VAR2"

इस बार ऊपर परीक्षण किया गया है।


मैं देख सकता हूँ कि आपने परीक्षण नहीं किया था! मुख्य तर्क काम करता है, लेकिन यह मुश्किल नहीं है। मुश्किल बिट चीजों को ठीक से उद्धृत कर रहा है, और आप ऐसा नहीं कर रहे हैं। चर जिनके मान नई-पंक्तियों होते हैं, की कोशिश करो ', *आदि
गाइल्स 'तथाकथित बुराई को रोकने जा रहा है'

echo "$LVALUE=\"$RVALUE\""के रूप में अच्छी तरह से newlines रखने के लिए माना जाता है और cfg_file में परिणाम इस तरह होना चाहिए: MY_VAR1 = "Line1 \ nLine 2" इस प्रकार जब eval MY_VAR1 में नई लाइनें भी शामिल होंगी। निश्चित रूप से आपको समस्याएँ हो सकती हैं यदि आपके संग्रहीत मूल्य में ही "चार हो। लेकिन उस पर भी ध्यान दिया जा सकता था।
vadimbog

1
Btw, क्यों नीचे वोट करने के लिए कुछ है जो सही ढंग से यहाँ पूछे गए सवाल का जवाब दे रहा है? ऊपर मेरे लिए बहुत अच्छा काम करता है और मेरी लिपियों में हर जगह का उपयोग करता है?
vadimbog
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.