বাশ স্ক্রিপ্টে ডিডি-স্টাইলের পরামিতি


19

আমি একটি বাশ স্ক্রিপ্ট, ডিডি-স্টাইলে পরমগুলি দিতে চাই। মূলত, আমি চাই

./script a=1 b=43

হিসাবে একই প্রভাব আছে

a=1 b=43 ./script

আমি ভেবেছিলাম আমি এটি দিয়ে এটি অর্জন করতে পারি:

for arg in "$@"; do
   eval "$arg";
done

evalএটি নিরাপদ, অর্থাৎ "$arg"একটি স্ট্যাটিক (কোনও কোড প্রয়োগ নয়), ভেরিয়েবল অ্যাসাইনমেন্টের সাথে মেলে তা নিশ্চিত করার একটি ভাল উপায় কী ?

অথবা এটি করার আরও ভাল উপায় আছে? (আমি এই সহজ রাখতে চাই)


এটি বাশ দিয়ে ট্যাগ করা হয়। আপনি কি একটি পিক্সিক্স কমপ্লায়েন্ট সমাধান চান, বা বাশ সমাধানগুলি গ্রহণ করবেন?
ধনী

ট্যাগটি যা বলে তা হ'ল আমার অর্থ :)
PSkocik

ঠিক আছে আপনি কেবল এটি একটি =বিভাজকের সাথে একটি প্যাটার্ন হিসাবে পার্স করতে পারেন এবং আরও যত্ন সহকারে নির্মিত ইওল দিয়ে অ্যাসাইনমেন্টটি করতে পারেন। কেবল সুরক্ষার জন্য, ব্যক্তিগত ব্যবহারের জন্য, আপনি এটি যেমনটি করেছিলেন তেমন চাই।
orion

উত্তর:


16

আপনি এটিকে বাশতে ছাড়িয়ে (এবং কৃত্রিম পলায়ন ছাড়াই) করতে পারেন:

for arg in "$@"; do
  if [[ $arg =~ ^[[:alpha:]_][[:alnum:]_]*= ]]; then
    declare +i +a +A "$arg"
  fi
done

সম্পাদনা: স্টাফেন চেজেলাসের একটি মন্তব্যের ভিত্তিতে, আমি ইতিমধ্যে অ্যারে বা পূর্ণসংখ্যার ভেরিয়েবল হিসাবে ঘোষিত ভেরিয়েবলটি এড়াতে ঘোষিত পতাকাগুলিতে যুক্ত করেছি, যা যুক্তিটির declareমান অংশটি মূল্যায়ন করবে এমন অনেকগুলি মামলা এড়াতে পারে key=val। ( +aভেরিয়েবলটি সেট করার জন্য যদি ইতিমধ্যে অ্যারে ভেরিয়েবল হিসাবে ঘোষণা করা হয় তবে এটির ফলে একটি ত্রুটি ঘটবে)) এই সমস্ত দুর্বলতা বিদ্যমান (অ্যারে বা পূর্ণসংখ্যার) ভেরিয়েবলগুলি পুনরায় সাইন করতে এই সিনট্যাক্সটি ব্যবহারের সাথে সম্পর্কিত যা সাধারণত সুপরিচিত হবে would শেল ভেরিয়েবল।

প্রকৃতপক্ষে, এটি কেবলমাত্র এক শ্রেণির ইনজেকশন আক্রমণগুলির উদাহরণ যা সমান evalভিত্তিক সমাধানগুলিকে প্রভাবিত করবে : কমান্ড-লাইনে যে কোনও ভেরিয়েবল উপস্থিত হতে পারে তা অন্ধভাবে সেট করার চেয়ে জানা যুক্তি নামগুলির অনুমতি দেওয়া সত্যিই অনেক ভাল। ( PATHউদাহরণস্বরূপ, কমান্ড লাইনটি সেট হলে কী হয় তা বিবেচনা করুন Or বা PS1কিছু মূল্যায়ন অন্তর্ভুক্ত করতে পুনরায় সেট করুন যা পরবর্তী প্রম্পট ডিসপ্লেতে ঘটবে))

ব্যাশ ভেরিয়েবল ব্যবহার না করে, আমি নামী যুক্তিগুলির একটি সাহচর্যমূলক অ্যারে ব্যবহার করতে পছন্দ করব, যা উভয়ই সেট করা সহজ এবং আরও নিরাপদ। বিকল্পভাবে, এটি প্রকৃত বাশ ভেরিয়েবলগুলি সেট করতে পারে তবে কেবল যদি তাদের নাম বৈধ তর্কগুলির মিশ্রিত বিন্যাসে থাকে।

পরের পদ্ধতির উদাহরণ হিসাবে:

# Could use this array for default values, too.
declare -A options=([bs]= [if]= [of]=)
for arg in "$@"; do
  # Make sure that it is an assignment.
  # -v is not an option for many bash versions
  if [[ $arg =~ ^[[:alpha:]_][[:alnum:]_]*= &&
        ${options[${arg%%=*}]+ok} == ok ]]; then
    declare "$arg"
    # or, to put it into the options array
    # options[${arg%%=*}]=${arg#*=}
  fi
done

1
রেজেক্স মনে হচ্ছে বন্ধনীটি ভুল আছে। সম্ভবত পরিবর্তে এই ব্যবহার করুন: ^[[:alpha:]_][[:alnum:]_]*=?
lcd047

1
@ lcd047: foo=খালি স্ট্রিংয়ে ফু সেট করার একমাত্র উপায়, সুতরাং এটির (আইএমএইচও) অনুমতি দেওয়া উচিত। আমি বন্ধনী স্থির করেছি, ধন্যবাদ।
ধনী

3
declareপ্রায় হিসাবে বিপজ্জনক eval(এক এমনকি এটি আরও বিপজ্জনক হিসাবে এটি স্পষ্ট হিসাবে না হিসাবে খারাপ বলতে পারে)। 'DIRSTACK=($(echo rm -rf ~))'যুক্তি হিসাবে কল করতে উদাহরণস্বরূপ চেষ্টা করুন ।
স্টাফেন চেজেলাস

1
@ স্পস্কিক: +x"নন -x" -a= সূচকযুক্ত অ্যারে, -A= সহযোগী অ্যারে, -i= পূর্ণসংখ্যার ভেরিয়েবল। সুতরাং: ইনডেক্সড অ্যারে নয়, এসোসিয়েটিভ অ্যারে নয়, পূর্ণসংখ্যা নয়।
lcd047

1
নোট করুন যে পরবর্তী সংস্করণটির সাথে bashআপনাকে +cযৌগিক পরিবর্তনগুলি +Fঅক্ষম করতে বা ভাসমানগুলি অক্ষম করতে হবে। evalআপনি যেখানে দাঁড়িয়ে আছেন তা আমি এখনও ব্যবহার করব ।
স্টাফেন চেজেলাস

9

একটি পজিক্স এক ( বিশেষ ভেরিয়েবলগুলির সাথে সমস্যাগুলি এড়াতে $<prefix>varপরিবর্তে সেট করে ... / )$varIFSPATH

prefix=my_prefix_
for var do
  case $var in
    (*=*)
       case ${var%%=*} in
         "" | *[!abcdefghijiklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_]*) ;;
         (*) eval "$prefix${var%%=*}="'${var#*=}'
       esac
  esac
done

নামে পরিচিত myscript x=1 PATH=/tmp/evil %=3 blah '=foo' 1=2, এটি বরাদ্দ করবে:

my_prefix_x <= 1
my_prefix_PATH <= /tmp/evil
my_prefix_1 <= 2

6

lcd047 এর সমাধানটি একটি হার্ডকডযুক্ত DD_OPT_উপসর্গের সাথে রিফ্যাক্টর :

while [[ $1 =~ ^[[:alpha:]_][[:alnum:]_]*= ]]; do
  eval "DD_OPT_${1%%=*}"='${1#*=}'; shift;
done

frostschutz রিফ্যাক্টরিংয়ের বেশিরভাগ the প্রাপ্য।

আমি বিশ্বব্যাপী ভেরিয়েবল হিসাবে এটি একটি উত্স ফাইলে রেখেছি:

DD_OPTS_PARSE=$(cat <<'EOF'
  while [[ $1 =~ ^[[:alpha:]_][[:alnum:]_]*= ]]; do
    eval "DD_OPT_${1%%=*}"='${1#*=}'; shift;
  done
EOF
)

eval "$DD_OPTS_PARSE" সমস্ত যাদু না।

ফাংশনগুলির জন্য একটি সংস্করণ হবে:

DD_OPTS_PARSE_LOCAL="${PARSE_AND_REMOVE_DD_OPTS/DD_OPT_/local DD_OPT_}"

ব্যাবহৃত হচ্ছে:

eval "$DD_OPTS_PARSE_LOCAL"

আমি এগুলির বাইরে একটি রেপো তৈরি করেছি , পরীক্ষা এবং README.md দিয়ে সম্পূর্ণ। তারপরে আমি এটি লিখেছিলাম একটি গিথুব এপিআই সিএলআই র‌্যাপারে ব্যবহার করেছিলাম এবং আমি একই রেপার ব্যবহার করে বললাম রেপোর একটি গিথুব ক্লোন সেটআপ করতে পারি (বুটস্ট্র্যাপিং মজাদার)।

মাত্র এক লাইনে বাশ স্ক্রিপ্টগুলির জন্য নিরাপদ প্যারামিটার উত্তরণ। উপভোগ করুন। :)


1
তবে আপনি পরিত্রাণ পেতে *=*এবং যেখানে কী নেই সেখানে কী / ভালটি প্রতিস্থাপন বন্ধ করতে পারেন । (যেহেতু আপনি রিফ্যাক্টর করছেন): পি
ফ্রয়েস্টচুটজ

1
আসলে আপনি লুপ এবং ইফ এবং এর পরিবর্তে $ 1 করার সময় ব্যবহার করতে পারেন, যেহেতু আপনি স্থান পরিবর্তন করছেন এবং সমস্ত ...
frostschutz

1
হেই, মস্তিষ্কে কাজ করার প্রমাণ। :)
lcd047

1
সকালের ধারণাগুলি সংগ্রহ করা: আপনি এমনকি এড়াতে keyএবং val, এবং কেবল লিখতেও পারেন eval "${1%%=*}"=\${1#*=}। তবে এটি যতটা যায় eval "$1"তেমনই যথেষ্ট , যেমন @ রিচি এর declare "$arg"কাজ করবে না, স্পষ্টতই। PATHবা পছন্দ মত জিনিস স্থাপন থেকে সাবধান PS1
lcd047

1
আপনাকে ধন্যবাদ - আমি ভেবেছিলাম এটিই মূল্যায়িত পরিবর্তনশীল। আমি আমার সাথে আপনার ধৈর্যকে প্রশংসা করি - এটি অত্যন্ত সুস্পষ্টভাবে সুস্পষ্ট। যাইহোক, না - কল্পনা করা ছাড়া অন্যটি দেখতে ভাল লাগে। আপনি যদি জানেন যে আপনি এটির সাথে কোনও শেলটিতে কাজ করতে প্রসারিত করতে পারেন case। সম্ভবত এটি কোনও ব্যাপার নয়, তবে কেবল আপনি যদি না জানতেন ...
মাইকসার্ভ

5

ক্লাসিক বোর্ন শেল সমর্থিত, এবং বাশ এবং কর্ন শেল এখনও সমর্থন করে, একটি -kবিকল্প। যখন এটি কার্যকর হয়, ddকমান্ড লাইনের যে কোনও ' -Like' কমান্ড বিকল্পগুলি স্বয়ংক্রিয়ভাবে কমান্ডে স্থান করা পরিবেশ ভেরিয়েবলগুলিতে রূপান্তরিত হয়:

$ set -k
$ echo a=1 b=2 c=3
$ 

তারা যে পরিবেশের পরিবর্তনশীল তা নিশ্চিত করে নেওয়া একটু কঠিন; এটি চালানো আমার পক্ষে কাজ করে:

$ set -k
$ env | grep '^[a-z]='   # No environment a, b, c
$ bash -c 'echo "Args: $*" >&2; env' a=1 b=2 c=3 | grep '^[a-z]='
Args: 
a=1
b=2
c=3
$ set +k
$ bash -c 'echo "Args: $*" >&2; env' a=1 b=2 c=3 | grep '^[a-z]='
Args: b=2 c=3
$

প্রথমটি env | grepএকটি একক ছোট-ছোট অক্ষরের সাথে কোনও পরিবেশের ভেরিয়েবল প্রদর্শন করে না। প্রথমটি bashদেখায় যে স্ক্রিপ্টটির মাধ্যমে কোনও আর্গুমেন্ট দেওয়া হয়নি -cএবং পরিবেশটিতে তিনটি একক-বর্ণের ভেরিয়েবল রয়েছে। set +kবাতিল -k, এবং শো যে একই কমান্ড এখন এটি পাস আর্গুমেন্ট নেই। ( স্ক্রিপ্ট a=1হিসাবে বিবেচিত হয়েছিল $0; আপনি যথাযথ প্রতিধ্বনির মাধ্যমেও তা প্রমাণ করতে পারেন))

এটি প্রশ্নটি যা জিজ্ঞাসা করে তা অর্জন করে - টাইপিং টাইপ করার মতো ./script.sh a=1 b=2হওয়া উচিত a=1 b=2 ./script.sh

আপনি যদি স্ক্রিপ্টের মধ্যে এর মতো কৌশল ব্যবহার করে থাকেন তবে আপনি সমস্যার মধ্যে পড়েছেন এ বিষয়ে সচেতন হন:

if [ -z "$already_invoked_with_minus_k" ]
then set -k; exec "$0" "$@" already_invoked_with_minus_k=1
fi

"$@"ধারণকৃত চিকিত্সা করা হয়; অ্যাসাইনমেন্ট-স্টাইলের ভেরিয়েবলগুলি (উভয় bashএবং উভয় ksh) সন্ধান করার জন্য এটি পুনরায় বিশ্লেষণ করা হয় না । আমি চেষ্টা করেছিলাম:

#!/bin/bash

echo "BEFORE"
echo "Arguments:"
al "$@"
echo "Environment:"
env | grep -E '^([a-z]|already_invoked_with_minus_k)='
if [ -z "$already_invoked_with_minus_k" ]
then set -k; exec "$0" "$@" already_invoked_with_minus_k=1
fi

echo "AFTER"
echo "Arguments:"
al "$@"
echo "Environment:"
env | grep -E '^([a-z]|already_invoked_with_minus_k)='

unset already_invoked_with_minus_k

এবং শুধুমাত্র already_invoked_with_minus_kপরিবেশ পরিবর্তনশীল exec'ডি স্ক্রিপ্টে সেট করা আছে ।


খুব সুন্দর উত্তর! এটি আকর্ষণীয় যে এটি প্যাথ পরিবর্তন করবে না, যদিও বাড়িটি পরিবর্তনযোগ্য, সুতরাং ব্ল্যাকলিস্টের মতো কিছু অন্তর্ভুক্ত থাকতে হবে (অন্ততপথ PATH রয়েছে) vভভ ভার্স যা এইভাবে সেট করা খুব বিপজ্জনক হতে পারে। আমি কীভাবে এটি অতি স্বল্প এবং এই প্রশ্নের উত্তরটির উত্তর দিচ্ছি, তবে আমি স্যানিটাইজ + ইভাল + উপসর্গের সমাধানটি নিয়ে যাব কারণ এটি এখনও নিরাপদ এবং এর ফলে আরও সর্বজনীনভাবে ব্যবহারযোগ্য (এমন পরিবেশে যেখানে আপনি চান না যে ব্যবহারকারীরা পরিবেশের সাথে ঝামেলা করতে পারে) )। ধন্যবাদ এবং +1।
পিএসকোকিক

2

আমার প্রচেষ্টা:

#! /usr/bin/env bash
name='^[a-zA-Z][a-zA-Z0-9_]*$'
count=0
for arg in "$@"; do
    case "$arg" in
        *=*)
            key=${arg%%=*}
            val=${arg#*=}

            [[ "$key" =~ $name ]] && { let count++; eval "$key"=\$val; } || break

            # show time
            if [[ "$key" =~ $name ]]; then
                eval "out=\${$key}"
                printf '|%s| <-- |%s|\n' "$key" "$out"
            fi
            ;;
        *)
            break
            ;;
    esac
done
shift $count

# show time again   
printf 'arg: |%s|\n' "$@"

এটি আরএইচএসে (প্রায়) নির্বিচারে আবর্জনা নিয়ে কাজ করে:

$ ./assign.sh Foo_Bar33='1 2;3`4"5~6!7@8#9$0 1%2^3&4*5(6)7-8=9+0' '1 2;3`4"5~6!7@8#9$0 1%2^3&4*5(6)7-8=9+0=33'
|Foo_Bar33| <-- |1 2;3`4"5~6!7@8#9$0 1%2^3&4*5(6)7-8=9+0|
arg: |1 2;3`4"5~6!7@8#9$0 1%2^3&4*5(6)7-8=9+0=33|

$ ./assign.sh a=1 b=2 c d=4
|a| <-- |1|
|b| <-- |2|
arg: |c|
arg: |d=4|

আপনি যদি প্রথম অ- x = y প্যারামিটারে লুপটি না ভাঙেন তবে শিফটটি ভুল জিনিসগুলি মেরে ফেলবে
frostschutz

@ ফ্রস্টসচুটজ গুড পয়েন্ট, সম্পাদিত।
lcd047

এটি সাধারণকরণে দুর্দান্ত কাজ আমি মনে করি এটি কিছুটা সহজ করা যায়।
পিএসকোকিক

আপনি আমার সম্পাদনাটি একবার দেখার সুযোগ পেয়েছেন?
পিএসকোকিক

আমার সম্পাদনা একবার দেখুন। এটি আমার পছন্দ মতো (+ সম্ভবত কেবল shiftপরিবর্তে shift 1)। নাহলে ধন্যবাদ!
পিএসকোকিক

0

কিছুক্ষণ আগে আমি aliasএই ধরণের কাজের জন্য স্থির হয়েছি । আমার আরও কিছু উত্তর এখানে দেওয়া হয়েছে:


যদিও কখনও কখনও এই জাতীয় বিবৃতিগুলির মূল্যায়ন এবং সম্পাদন পৃথক করা সম্ভব হয়। উদাহরণস্বরূপ, aliasকমান্ডের প্রাক-মূল্যায়ন করতে ব্যবহার করা যেতে পারে। নিম্নলিখিত উদাহরণে ভেরিয়েবল সংজ্ঞা একটি উপাধিতে সংরক্ষণ করা হয় যা কেবলমাত্র সফলভাবে ঘোষণা করা যেতে পারে যদি $varএটির পরিবর্তনশীলটি মূল্যায়ন করছে তবে এমন কোনও বাইট নেই যা ASCII বর্ণানুক্রমিক বা _ এর সাথে মেলে না।

LC_OLD=$LC_ALL LC_ALL=C
for var do    val=${var#*=} var=${var%%=*}
    alias  "${var##*[!_A-Z0-9a-z]*}=_$var=\$val" &&
    eval   "${var##[0-9]*}" && unalias "$var"
done;       LC_ALL=$LC_OLD

evalএখানে aliasউদ্ধৃত বর্ণনামের প্রসঙ্গটি থেকে নতুনকে আহ্বান করতে পরিচালনা করতে ব্যবহার করা হয়েছে - অ্যাসাইনমেন্টের জন্য ঠিক নয়। আর evalশুধুমাত্র বলা হয় এ সব যদি পূর্ববর্তী aliasসংজ্ঞা সফল হয়, এবং যখন আমি বিভিন্ন বাস্তবায়নের অনেক জানেন ওরফে নামের জন্য মান বিভিন্ন ধরণের অনেক গ্রহণ করবে, আমি এখনো একটি শেল করে একটি সম্পূর্ণ খালি এক গ্রহণ করবে পাওয়া যায় ।

উপন্যাসের মধ্যে সংজ্ঞাটি _$varঅবশ্য এর জন্য, এবং এটি কোনও নিশ্চিত পরিবেশের মানগুলি রচিত না হয় তা নিশ্চিত করা। আমি _ এর সাথে শুরু হওয়া কোনও উল্লেখযোগ্য পরিবেশের মান জানি না এবং এটি প্রায়শই আধা-বেসরকারী ঘোষণার জন্য একটি নিরাপদ বাজি।

যাইহোক, যদি উপনাম সংজ্ঞাটি সফল হয় তবে এটির $varমানটির জন্য একটি উপনাম ঘোষণা করবে । এবং evalকেবলমাত্র এটি কল করবে aliasযদি এটি একটি সংখ্যা দিয়ে শুরু না হয় - অন্যথায় evalকেবল একটি নাল যুক্তি পায়। সুতরাং যদি উভয় শর্ত পূরণ evalহয় aliasএবং কলটি সংরক্ষণ করা হয় এবং সেভের পরিবর্তিত সংজ্ঞাটি aliasতৈরি করা হয়, তারপরে হ্যাশ টেবিল থেকে তাত্ক্ষণিকভাবে নতুন উপনাম সরিয়ে ফেলা হয়।


aliasএই প্রসঙ্গে এছাড়াও দরকারী আপনি আপনার কাজ মুদ্রণ করতে পারেন। জিজ্ঞাসা করা হলে aliasএকটি দ্বিগুণ-উদ্ধৃত শেল-রেক্স্যাকিউশন বিবৃতি মুদ্রণ করবে ।

sh -c "IFS=\'
    alias q=\"\$*\" q" -- \
    some args which alias \
    will print back at us

আউটপুট

q='some'"'"'args'"'"'which'"'"'alias'"'"'will'"'"'print'"'"'back'"'"'at'"'"'us'
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.