बैश और zsh में डबल और ट्रिपल प्रतिस्थापन


23

इस प्रश्न में पृष्ठभूमि भाग का अनुसरण करें ।

में bashमैं ${!FOO}डबल प्रतिस्थापन के लिए उपयोग कर सकते हैं , में zsh ${(P)FOO}। दोनों में, पुराने स्कूल (हैक-वाई) eval \$$FOOकाम करता है।

तो, मेरे लिए सबसे चतुर और सबसे तार्किक बात ${${FOO}}, ${${${FOO}}}…डबल / ट्रिपल / एन प्रतिस्थापन के लिए होगी। यह काम उम्मीद के मुताबिक क्यों नहीं हुआ?

दूसरा: बयान \में क्या करता है eval? मुझे लगता है यह एक भागने है, eval \$$$FOOअसंभव जैसा कुछ बना रही है । प्रत्येक शेल में काम करने वाले ट्रिपल / एन प्रतिस्थापन के साथ कैसे करें?

जवाबों:


15

\के विस्तार को रोकने के लिए इस्तेमाल किया जाना चाहिए $$(वर्तमान प्रक्रिया आईडी)। ट्रिपल प्रतिस्थापन के लिए, आपको डबल eval की आवश्यकता होती है, इसलिए प्रत्येक eval में अवांछित विस्तार से बचने के लिए और भी अधिक पलायन:

#! /bin/bash
l0=value
l1=l0
l2=l1
l3=l2
l4=l3

echo $l0
eval echo \$$l1
eval eval echo \\$\$$l2
eval eval eval echo \\\\$\\$\$$l3
eval eval eval eval echo \\\\\\\\$\\\\$\\$\$$l4

अभी तक: l3=l2; eval eval eval echo \\\$\\$\$$l353294तो बिल्कुल मॉड्यूलर नहीं।
प्रोफैट्स

2
मैं ऐसा कुछ क्यों नहीं कर सकता eval $(eval echo \$$l2)? मैं बैश से नफरत करता हूं, यह बिल्कुल समझ में नहीं आता है।
प्रोफैट्स

@Profpatsch: और उदाहरण जोड़े गए।
कोरोबा

आह, यह n² है। मैं यह भी पाने की कोशिश नहीं करना चाहता कि ऐसा क्यों है।
प्रोफैट्स

2
@Profpatsch: आसान। प्रत्येक चरण में, बैकस्लैश की संख्या घट जाती है (इसलिए यह 2 in है, वास्तव में)।
कोरोबा


6

मान FOOलेना एक मान्य चर नाम (कहना BAR) है, अलग-अलग शब्दों eval \$$FOOके मूल्य को विभाजित BARकरता है, प्रत्येक शब्द को वाइल्डकार्ड पैटर्न के रूप में मानता है, और परिणाम के पहले शब्द को कमांड के रूप में निष्पादित करता है, दूसरे शब्दों को तर्क के रूप में पारित करता है। डॉलर के सामने बैकस्लैश का शाब्दिक रूप से इलाज किया जाता है, इसलिए evalबिलिन को दिया गया तर्क चार-वर्ण स्ट्रिंग है $BAR

${${FOO}}एक वाक्यविन्यास त्रुटि है। यह एक "डबल प्रतिस्थापन" नहीं करता है क्योंकि किसी भी सामान्य गोले में ऐसी कोई विशेषता नहीं है (वैसे भी इस वाक्यविन्यास के साथ नहीं)। Zsh में, ${${FOO}} है वैध और एक डबल प्रतिस्थापन है, लेकिन यह आप चाहें तो क्या से अलग ढंग से व्यवहार करती है: यह के मूल्य पर लगातार दो परिवर्तनों प्रदर्शन करती है FOO, जो दोनों के पहचान परिवर्तन कर रहे हैं, तो यह लिखने का सिर्फ एक आधुनिक तरीका है ${FOO}

यदि आप किसी चर के मूल्य को चर के रूप में मानना ​​चाहते हैं, तो चीजों को ठीक से उद्धृत करने से सावधान रहें। यदि आप परिणाम को एक चर पर सेट करते हैं तो यह बहुत आसान है:

eval "value=\${$FOO}"

1
इसे चर के रूप में सेट करना, ताकि पहला शब्द कमांड के रूप में उपयोग न हो? यार, इस तरह के तर्क को समझ पाना कठिन है। यह सामान्य समस्या है जो मुझे लगता है कि बैश है।
प्रोफैट्स

4

{ba,z}sh समाधान

यहां एक फ़ंक्शन है जो दोनों में काम करता है {ba,z}sh। मेरा मानना ​​है कि यह भी POSIX आज्ञाकारी है।

उद्धरण के साथ पागल हुए बिना, आप इसे अप्रत्यक्ष के कई स्तरों के लिए उपयोग कर सकते हैं जैसे:

$ a=b
$ b=c
$ c=d
$ echo $(var_expand $(var_expand $a)
d

या यदि आपके पास अधिक (!!) परोक्ष का स्तर है तो आप एक लूप का उपयोग कर सकते हैं।

यह दिए जाने पर चेतावनी देता है:

  • अशक्त इनपुट
  • एक चर नाम जो सेट नहीं है

# Expand the variable named by $1 into its value. Works in both {ba,z}sh
# eg: a=HOME $(var_expand $a) == /home/me
var_expand() {
  if [ -z "${1-}" ] || [ $# -ne 1 ]; then
    printf 'var_expand: expected one argument\n' >&2;
    return 1;
  fi
  eval printf '%s' "\"\${$1?}\""
}

मेरे लिए एक काम कर रहे क्रॉस-शेल समाधान। उम्मीद है कि "POSIX- संगत डबल चर विस्तार" भविष्य में इस उत्तर को पुनर्निर्देशित करता है।
ब्लूड्रिंक

2

जैसे की ${$foo}जगह काम नहीं करता ${(P)foo}है zsh, न ही करता है ${${$foo}}। आपको बस अप्रत्यक्ष के प्रत्येक स्तर को निर्दिष्ट करने की आवश्यकता है:

$ foo=bar
$ bar=baz
$ baz=3
$ echo $foo
bar
$ echo ${(P)foo}
baz
$ echo ${(P)${(P)foo}}
3

बेशक, ${!${!foo}}काम नहीं करता है bash, क्योंकि bashनेस्टेड प्रतिस्थापन की अनुमति नहीं देता है।


धन्यवाद, यह जानना अच्छा है। यह शर्म की बात है कि यह केवल zsh है, इसलिए आप इसे वास्तव में एक स्क्रिप्ट में नहीं डाल सकते हैं (हर किसी को बैश है, लेकिन यह दूसरा तरीका नहीं है)।
१६:३० पर प्रोपटैस

मुझे संदेह zshहै कि आप जितनी बार मान सकते हैं, उससे कहीं अधिक बार स्थापित किया गया है। यह अक्सर (लेकिन हमेशा नहीं) की shतरह जुड़ा नहीं हो सकता bashहै, लेकिन यह अभी भी शेल स्क्रिप्ट के लिए उपलब्ध हो सकता है। इसे ऐसे समझें कि आप पर्ल या पायथन करते हैं।
चेपनर

2

आपको ऐसा करने की आवश्यकता क्यों होगी?

आप इसे हमेशा कई चरणों में कर सकते हैं जैसे:

eval "l1=\${$var}"
eval "l2=\${$l1}"
...

या एक फ़ंक्शन का उपयोग करें:

deref() {
  if [ "$1" -le 0 ]; then
    eval "$3=\$2"
  else
    eval "deref $(($1 - 1)) \"\${$2}\" \"\$3\""
  fi
}

फिर:

$ a=b b=c c=d d=e e=blah
$ deref 3 a res; echo "$res"
d
$ deref 5 a res; echo "$res"
blah

FWIW zsh: में

$ echo ${(P)${(P)${(P)${(P)a}}}}
blah

हुह, कई चरणों का उपयोग करते हुए मेरे पास अब तक नहीं था ... अजीब।
प्रॉस्पेक्ट

यह स्पष्ट है, मेरे दृष्टिकोण से, @Profpatsch ऐसा क्यों करना चाहता है । क्योंकि यह इसे करने का सबसे सहज तरीका है। होने के नाते कठिन बैश में एक से अधिक प्रतिस्थापन लागू करने के लिए एक और बात है।
निकोस एलेक्जेंड्रिस

2

POSIX समाधान

उद्धरण के साथ पागल हुए बिना, आप इस फ़ंक्शन का उपयोग अप्रत्यक्ष के कई स्तरों के लिए कर सकते हैं जैसे:

$ a=b
$ b=c
$ c=d
$ echo $(var_expand $(var_expand $a)
d

या यदि आपके पास अधिक (!!) परोक्ष का स्तर है तो आप एक लूप का उपयोग कर सकते हैं।

यह दिए जाने पर चेतावनी देता है:

  • अशक्त इनपुट
  • एक से अधिक तर्क
  • एक चर नाम जो सेट नहीं है

# Expand the variable named by $1 into its value. Works in both {ba,z}sh
# eg: a=HOME $(var_expand $a) == /home/me
function var_expand {
  if [ "$#" -ne 1 ] || [ -z "${1-}" ]; then
    printf 'var_expand: expected one argument\n' >&2;
    return 1;
  fi
  eval printf '%s' "\"\${$1?}\""
}

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