ব্যাশ এবং zsh এ ডাবল এবং ট্রিপল প্রতিস্থাপন


23

এই প্রশ্নের ব্যাকগ্রাউন্ড অংশ অনুসরণ করুন ।

ইন bashআমি ${!FOO}ডাবল প্রতিস্থাপনের জন্য ব্যবহার করতে পারেন zsh ${(P)FOO}। উভয়ই, পুরানো-স্কুল (হ্যাক-ওয়াই) eval \$$FOOকাজ করে।

সুতরাং, আমার জন্য স্মার্ট এবং সবচেয়ে যুক্তিযুক্ত জিনিসটি ${${FOO}}, ${${${FOO}}}…ডাবল / ট্রিপল / এন প্রতিস্থাপনের জন্য হবে। প্রত্যাশার মতো এই কাজটি কেন হয় না?

দ্বিতীয়ত: কী \না evalবক্তব্য? আমি মনে করি এটি একটি পালানো, eval \$$$FOOঅসম্ভব কিছু তৈরি করে । প্রতিটি শেলের সাথে কাজ করে এমন একটি ট্রিপল / এন বিকল্প কীভাবে করবেন?

উত্তর:


15

\সম্প্রসারণ রোধ করার জন্য ব্যবহার করা আবশ্যক $$(বর্তমান প্রক্রিয়া ID)। ট্রিপল প্রতিস্থাপনের জন্য, আপনার ডাবল বিভাজন প্রয়োজন, তেমনি প্রতিটি ক্রিয়াকলাপে অযাচিত বিস্তৃতি এড়াতে আরও পালাতে হবে:

#! /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)? আমি বাশকে ঘৃণা করি, এটি একেবারেই কোনও ধারণা রাখে না।
প্রোফ্যাপাটস

@ প্রফটপ্যাশ: আরও উদাহরণ যুক্ত করা হয়েছে।
চোরোবা

আহ, এটা না এমনকি কেন এটি এমন হয় তা জানার চেষ্টা করতে চাই না।
প্রোফ্যাপাটস

2
@ প্রফটপাটস: সহজ। প্রতিটি পদক্ষেপে ব্যাকস্ল্যাশগুলি অর্ধেকের সংখ্যা (সুতরাং এটি আসলে 2ⁿ)।
চোরোবা


6

মনে করুন মানটির FOOএকটি বৈধ পরিবর্তনশীল নাম (বলুন BAR), পৃথক শব্দের eval \$$FOOমানকে BARপৃথক করে, প্রতিটি শব্দকে একটি ওয়াইল্ডকার্ড প্যাটার্ন হিসাবে বিবেচনা করে এবং ফলাফলের প্রথম শব্দটি একটি আদেশ হিসাবে কার্যকর করে, অন্য শব্দগুলিকে আর্গুমেন্ট হিসাবে পাস করে। ডলারের সামনে ব্যাকস্ল্যাশ এটি আক্ষরিকভাবে চিকিত্সা করে তোলে, তাই evalবিল্টিনে দেওয়া আর্গুমেন্টটি চার অক্ষরের স্ট্রিং $BAR

${${FOO}}একটি সিনট্যাক্স ত্রুটি। এটি একটি "ডাবল প্রতিস্থাপন" করে না কারণ সাধারণ শেলগুলির কোনওর মধ্যে এই জাতীয় কোনও বৈশিষ্ট্য নেই (যাইহোক এই সিনট্যাক্সের সাথে নয়)। Zsh সালে ${${FOO}} হয় বৈধ এবং একটি ডবল প্রতিকল্পন, কিন্তু এটা আপনি চান কি থেকে ভিন্নভাবে আচরণ করবে: এটা মান দুটি ধারাবাহিক রূপান্তরের সঞ্চালিত FOO, এই দুই ধরনের পরিচয় রূপান্তর হয়, তাই এটি লেখার শুধু একটি অভিনব উপায় ${FOO}

আপনি যদি কোনও ভেরিয়েবলের মান একটি ভেরিয়েবল হিসাবে বিবেচনা করতে চান তবে জিনিসগুলি সঠিকভাবে উদ্ধৃত করার ক্ষেত্রে সতর্ক হন। আপনি যদি কোনও পরিবর্তনকে ফলাফল সেট করেন তবে এটি অনেক সহজ:

eval "value=\${$FOO}"

1
এটিকে পরিবর্তনশীল হিসাবে সেট করা, যাতে প্রথম শব্দটি কমান্ড হিসাবে ব্যবহৃত হয় না? ম্যান, এই ধরণের যুক্তি বোঝা শক্ত। বাশ নিয়ে আমার মনে হয় এটি সাধারণ সমস্যা।
প্রোফ্যাচচ

4

{ba,z}sh সমাধান

এখানে একটি ফাংশন যা উভয় ক্ষেত্রেই কাজ করে {ba,z}sh। আমি বিশ্বাস করি এটি পসিক্সের অনুগতও।

উদ্ধৃতি দিয়ে পাগল না হয়ে আপনি এটিকে এ জাতীয় অনেকগুলি নির্দেশের জন্য ব্যবহার করতে পারেন:

$ 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- সামঞ্জস্যপূর্ণ ডাবল ভেরিয়েবল প্রসারণ" ভবিষ্যতে এই উত্তরে পুনর্নির্দেশ করে।
ব্লুড্রিঙ্ক 9

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

এফডাব্লুআইডাব্লু, এতে 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?}\""
}

আপনি এই উত্তরটি আপনার আগের উত্তরটির সাথে সংযুক্ত না করার কোনও কারণ আছে? এক নজরে আমি তাদের মধ্যে পার্থক্য দেখতে পাচ্ছি না।
ব্লুড্রিঙ্ক 9
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.