বাশ প্যারামিটার অ্যারের সূচক এবং সংশোধন করছে $ @


11

ইনডেক্সগুলি উল্লেখ করা কি সম্ভব $@? আমি গ্রেগেটের উইকিতে কোথাও নীচের মত ব্যবহারের জন্য কোনও রেফারেন্স খুঁজে পাচ্ছি না , এবং উন্নত স্ক্রিপ্টিং গাইড এবং অন্যরা পরিবর্তে পরিবর্তনের আগে এটিকে ভিন্ন ভেরিয়েবলের জন্য নির্ধারণ করে।

$ echo ${@[0]}
-bash: ${@[0]}: bad substitution

লক্ষ্যটি ডিআরওয়াই : প্রথম যুক্তিটি একটি জিনিসের জন্য ব্যবহার করা হয়, এবং বাকী অন্য কোনও কিছুর জন্য এবং আমি কোডটি স্বাভাবিক করার জন্য, $@অ্যারে বা এর জন্য একটি পৃথক ফাংশন তৈরির অনুলিপি এড়াতে চাই (যদিও এই সময়ে এটি সম্ভবত সবচেয়ে সহজ উপায়) পয়েন্ট।

ব্যাখ্যা: বস্তুর মান পরিবর্তন করতে ছিল পরিবর্তনশীল দৈর্ঘ্যের $@ করতে কোড ডিবাগ করা আরো সহজ। বর্তমান সংস্করণটি আমার পছন্দ হিসাবে কিছুটা হ্যাকি, যদিও এটি এমনকি উদ্ভট পথগুলির জন্য এমনকি কাজ করে

$'--$`\! *@ \a\b\e\E\f\r\t\v\\\"\' \n'

আপডেট : দেখে মনে হচ্ছে এটি সম্ভব নয়। কোডটি এখন উভয় কোড এবং ডেটা সদৃশ ব্যবহার করে তবে কমপক্ষে এটি কাজ করে:

path_common()
{
    # Get the deepest common path.
    local common_path="$(echo -n "${1:-}x" | tr -s '/')"
    common_path="${common_path%x}"
    shift # $1 is obviously part of $1
    local path

    while [ -n "${1+defined}" ]
    do
        path="$(echo -n "${1}x" | tr -s '/')"
        path="${path%x}"
        if [[ "${path%/}/" = "${common_path%/}/"* ]]
        then
            shift
        else
            new_common_path="${common_path%/*}"
            [ "$new_common_path" = "$common_path" ] && return 1 # Dead end
            common_path="$new_common_path"
        fi
    done
    printf %s "$common_path"
}

অনুগ্রহ যারা পরিত্রাণ পেতে পারেন যায় কোডের অনুলিপি ডুপ্লিকেট স্ল্যাশ বা সঙ্কুচিত করতে ডেটার অনুলিপি রাখা $1এবং অন্যান্য পরামিতি, অথবা উভয়, কোড একটি যুক্তিসঙ্গত আকার রেখে এবং সব ইউনিট পরীক্ষা সফল যখন:

test "$(path_common /a/b/c/d /a/b/e/f; echo x)" = /a/bx
test "$(path_common /long/names/foo /long/names/bar; echo x)" = /long/namesx
test "$(path_common / /a/b/c; echo x)" = /x
test "$(path_common a/b/c/d a/b/e/f ; echo x)" = a/bx
test "$(path_common ./a/b/c/d ./a/b/e/f; echo x)" = ./a/bx
test "$(path_common $'\n/\n/\n' $'\n/\n'; echo x)" = $'\n/\n'x
test "$(path_common --/-- --; echo x)" = '--x'
test "$(path_common '' ''; echo x)" = x
test "$(path_common /foo/bar ''; echo x)" = x
test "$(path_common /foo /fo; echo x)" = x
test "$(path_common $'--$`\! *@ \a\b\e\E\f\r\t\v\\\"\' \n' $'--$`\! *@ \a\b\e\E\f\r\t\v\\\"\' \n'; echo x)" = $'--$`\! *@ \a\b\e\E\f\r\t\v\\\"\' \n'x
test "$(path_common /foo/bar //foo//bar//baz; echo x)" = /foo/barx
test "$(path_common foo foo; echo x)" = foox
test "$(path_common /fo /foo; echo x)" = x

উত্তর:


16

POSIX

সমস্ত পরামিতিগুলিতে স্ল্যাশগুলি স্বাভাবিক করার জন্য, আমি ঘোরানো আর্গুমেন্ট ট্রিকটি ব্যবহার করব: শিফট $1অফ করুন, এটিকে রূপান্তর করুন এবং ফলাফলটিকে প্যারামিটার তালিকার শেষে রাখবেন। আপনি যদি প্যারামিটারগুলি যতটা সময় ব্যবহার করেন তবে আপনি সমস্ত প্যারামিটারগুলি রূপান্তর করেছেন এবং সেগুলি যথাযথভাবে ফিরে পেয়েছেন।

কোডের দ্বিতীয় অংশের জন্য, আমি আপনার যুক্তিটিকে কম বিভ্রান্তিতে পরিণত করেছি: বাহ্যিক লুপটি পরামিতিগুলির উপরে পুনরাবৃত্তি করে, এবং অভ্যন্তরীণ লুপটি পথের উপাদানগুলিতে পুনরাবৃত্তি করে। for x; do … doneঅবস্থানগত পরামিতিগুলি পুনরাবৃত্তি করে, এটি একটি সুবিধাজনক প্রতিমা। আমি কোনও প্যাটার্নের সাথে স্ট্রিংয়ের সাথে মিলের একটি পসিক্স-অনুপযুক্ত উপায় ব্যবহার করি: caseকনস্ট্রাক্ট।

ড্যাশ 0.5.5.1.1, পিডিএক্স 5.2.14, ব্যাশ 3.2.39, ব্যাশ 4.1.5, কেএসএস 93 এস +, জেডএস 4.3.10 পরীক্ষিত।

পার্শ্ব দ্রষ্টব্য: ব্যাশ ৪.১.৫ এ একটি বাগ রয়েছে বলে মনে হচ্ছে (৩.২-তে নয়): কেস প্যাটার্নটি থাকলে "${common_path%/}"/*পরীক্ষার মধ্যে একটি ব্যর্থ হয়।

posix_path_common () {
  for tmp; do
    tmp=$(printf %s. "$1" | tr -s "/")
    set -- "$@" "${tmp%.}"
    shift
  done
  common_path=$1; shift
  for tmp; do
    while case ${tmp%/}/ in "${common_path%/}/"*) false;; esac; do
      new_common_path=${common_path%/*}
      if [ "$new_common_path" = "$common_path" ]; then return 1; fi
      common_path=$new_common_path
    done
  done
  printf %s "$common_path"
}

bash, ksh

আপনি বাশ (বা কেএসএস) এ থাকলে আপনি অ্যারে ব্যবহার করতে পারেন - আপনি কেন অবস্থানিক পরামিতিগুলিতে নিজেকে সীমাবদ্ধ রাখছেন বলে মনে হয় না। এখানে একটি সংস্করণ যা অ্যারে ব্যবহার করে। আমাকে স্বীকার করতে হবে যে এটি পসিক্স সংস্করণের চেয়ে স্পষ্ট নয়, তবে এটি প্রাথমিক এন ^ 2 এলোমেলো এড়ায় না।

স্ল্যাশ নিয়মমাফিককরণ অংশ জন্য, আমি ksh93 কনস্ট্রাক্ট ব্যবহার ${foo//PATTERN/REPLACEMENT}কনস্ট্রাক্ট এর সমস্ত সংঘটন প্রতিস্থাপন PATTERNমধ্যে $fooদ্বারা REPLACEMENT। প্যাটার্নটি +(\/)এক বা একাধিক স্ল্যাশের সাথে মেলে; ব্যাশের অধীনে, shopt -s extglobকার্যকর হওয়া আবশ্যক (সমতুল্যভাবে, এর সাথে ব্যাশ শুরু করুন bash -O extglob)। কনস্ট্রাক্ট set ${!a[@]}অ্যারের সাবস্ক্রিপ্টগুলির তালিকায় অবস্থানগত পরামিতিগুলি সেট করে a। এটি অ্যারের উপাদানগুলির উপর পুনরাবৃত্তি করার একটি সুবিধাজনক উপায় সরবরাহ করে।

দ্বিতীয় অংশের জন্য, আমি পসিক্স সংস্করণ হিসাবে একই লুপ লজিক। এই মুহুর্তে, আমি [[ … ]]এখানে লক্ষ্যযুক্ত সমস্ত শেলগুলি সমর্থন করার কারণে এটি ব্যবহার করতে পারি।

বাশ 3.2.39, বাশ 4.1.5, কেএসএস 93 এস + সহ পরীক্ষিত।

array_path_common () {
  typeset a i tmp common_path new_common_path
  a=("$@")
  set ${!a[@]}
  for i; do
    a[$i]=${a[$i]//+(\/)//}
  done
  common_path=${a[$1]}; shift
  for tmp; do
    tmp=${a[$tmp]}
    while [[ "${tmp%/}/" != "${common_path%/}/"* ]]; do
      new_common_path="${common_path%/*}"
      if [[ $new_common_path = $common_path ]]; then return 1; fi
      common_path="$new_common_path"
    done
  done
  printf %s "$common_path"
}

zsh

দুঃখের বিষয়, zsh এর ${!array[@]}হিসাবে ksh93 সংস্করণটি চালানোর জন্য বৈশিষ্ট্যটির অভাব রয়েছে । ভাগ্যক্রমে, zsh এর দুটি বৈশিষ্ট্য রয়েছে যা প্রথম অংশটিকে বাতাস করে তোলে। আপনি অবস্থানগত পরামিতিগুলি সূচী করতে পারেন যেমন সেগুলি @অ্যারে ছিল তাই মধ্যবর্তী অ্যারে ব্যবহার করার দরকার নেই। এবং zsh এর একটি অ্যারে পুনরাবৃত্তি কন্সট্রাক্ট রয়েছে : "${(@)array//PATTERN/REPLACEMENT}"প্রতিটি অ্যারে উপাদানের উপর প্যাটার্ন প্রতিস্থাপনটি ঘটা করে এবং ফলাফলগুলির অ্যারের মূল্যায়ন করে (বিভ্রান্তিকরভাবে, ফলাফলটি একাধিক শব্দের হলেও আপনাকে দ্বিগুণ উদ্ধৃতি প্রয়োজন; এটি সাধারণীকরণ "$@") is দ্বিতীয় অংশটি মূলত অপরিবর্তিত।

zsh_path_common () {
  setopt local_options extended_glob
  local tmp common_path new_common_path
  set -- "${(@)@//\/##//}"
  common_path=$1; shift
  for tmp; do
    while [[ "${tmp%/}/" != "${common_path%/}/"* ]]; do
      new_common_path="${common_path%/*}"
      if [[ $new_common_path = $common_path ]]; then return 1; fi
      common_path="$new_common_path"
    done
  done
  printf %s "$common_path"
}

পরীক্ষার মামলা

আমার সমাধানগুলি সর্বনিম্ন পরীক্ষিত এবং মন্তব্য করা হয়েছে। আমি আপনার পরীক্ষার কেসগুলির বাক্য গঠনটি এমন শেলগুলির নীচে পার্স করার জন্য পরিবর্তন করেছি $'…'এবং আরও সুবিধাজনক উপায়ে ব্যর্থতার প্রতিবেদন করছি।

do_test () {
  if test "$@"; then echo 0; else echo $? "$@"; failed=$(($failed+1)); fi
}

run_tests () {
  function_to_test=$1; shift
  failed=0
  do_test "$($function_to_test /a/b/c/d /a/b/e/f; echo x)" = /a/bx
  do_test "$($function_to_test /long/names/foo /long/names/bar; echo x)" = /long/namesx
  do_test "$($function_to_test / /a/b/c; echo x)" = /x
  do_test "$($function_to_test a/b/c/d a/b/e/f ; echo x)" = a/bx
  do_test "$($function_to_test ./a/b/c/d ./a/b/e/f; echo x)" = ./a/bx
  do_test "$($function_to_test '
/
/
' '
/
'; echo x)" = '
/
'x
  do_test "$($function_to_test --/-- --; echo x)" = '--x'
  do_test "$($function_to_test '' ''; echo x)" = x
  do_test "$($function_to_test /foo/bar ''; echo x)" = x
  do_test "$($function_to_test /foo /fo; echo x)" = x
  do_test "$($function_to_test '--$`\! *@ \a\b\e\E\f\r\t\v\\\"'\'' 
' '--$`\! *@ \a\b\e\E\f\r\t\v\\\"'\'' 
'; echo x)" = '--$`\! *@ \a\b\e\E\f\r\t\v\\\"'\'' 
'x
  do_test "$($function_to_test /foo/bar //foo//bar//baz; echo x)" = /foo/barx
  do_test "$($function_to_test foo foo; echo x)" = foox
  do_test "$($function_to_test /fo /foo; echo x)" = x
  if [ $failed -ne 0 ]; then echo $failed failures; return 1; fi
}

1
+50, শুধু বাহ! আমি যে হারে চেয়েছি চেয়ে বেশি। স্যার, আপনি দুর্দান্ত।
l0b0

পসিক্স আলোচনায়, প্রথম লুপে যেখানে আপনি স্ল্যাশগুলি স্বাভাবিক করেন, কেন সংযোজন "।" স্প্রিন্টফের সাথে আবার এটি পরের লাইনে ফেলে দিন? কোডটি এটি ব্যতীত কাজ করে বলে মনে হচ্ছে, তবে আমার সন্দেহ হয় যে আপনি একটি ধার্য মামলাটি পরিচালনা করছেন যা সম্পর্কে আমি অজানা।
অ্যালান ডি স্মেট

1
@ অ্যালানডিসমেট প্রান্ত কেসটি যদি স্ট্রিংটি একটি নতুন লাইনের সাথে শেষ হয়। কমান্ড প্রতিস্থাপন নতুন লাইনের পিছনে স্ট্রিপস।
গিলস 'অসন্তুষ্ট হওয়া বন্ধ করুন'

6

আপনি কেন কেবলমাত্র $ 1, $ 2 .. $ 9, $ {10}, $ {11} .. ইত্যাদি ব্যবহার করবেন না? আপনি যা করার চেষ্টা করছেন তার থেকেও এটি আরও বেশি শুকনো :)

$ সংখ্যা এবং $ @ এর মধ্যে সম্পর্কের বিষয়ে আরও :

all @ "সমস্ত তর্কযুক্ত একটি অ্যারের সমস্ত উপাদান" এর জন্য শর্টহ্যান্ড হিসাবে বিবেচিত হতে পারে

সুতরাং, $ @ হ'ল $ gs টি আর্গুমেন্ট [@]} এর শর্টহ্যান্ড gs (এখানে আর্টসগুলি একটি 'ভার্চুয়াল' অ্যারে যাতে সমস্ত আর্গুমেন্ট রয়েছে - আসল পরিবর্তনশীল নয়, মনে রাখবেন)

$ 1 হ'ল $ {টি আর্কস [1]}, $ 2 হ'ল gs gs টি [2]।, এবং আরও অনেক কিছু on

আপনি যখন [9] টি আঘাত করেছেন, তখন একটি ধনুর্বন্ধনী ব্যবহার করুন: $} 10} হ'ল gs gs টি আর্গ [10]।, $ {11 $ হল $ gs আর্গ [11]।, এবং আরও কিছু।


পরোক্ষভাবে একটি কমান্ড লাইন আর্গুমেন্ট ব্যবহার করুন

argnum=3  # You want to get the 3rd arg
do-something ${!argnum}  # Do something with the 3rd arg

উদাহরণ:

argc=$#
for (( argn=1; argn<=argc; argn++)); do
    if [[ ${!argn} == "foo" ]]; then
        echo "Argument $argn of $argc is 'foo'"
    fi
done

* সংখ্যা * ব্যবহার করার সুস্পষ্ট নেতিবাচকতা হ'ল আপনি ইন্ডেক্স ভেরিয়েবলটি আর ব্যবহার করতে পারবেন না ${args[$i]}
প্রেরণা

@intuited তারপরে ইন্ডিয়ারেশন ব্যবহার করুন; আমি আমার উত্তর সম্পাদনা করব।
পেপলুয়ান

5

প্রথম যুক্তিটি একটি জিনিসের জন্য ব্যবহার করা হয়, এবং বাকী অন্য কোনও কিছুর জন্য,

আমার মনে হয় আপনি যা চান তা shift

$ set one two three four five
$ echo $@
one two three four five
$ echo $1
one
$ foo=$1
$ echo $foo
one
$ shift
$ echo $@
two three four five
$ shift 2
$ echo $@
four five
$ echo $1
four

1

আমি কেন জানি না আপনি কেবল $ 1 $ 2 ইত্যাদি ব্যবহার করেন না .. তবে .. এটি আপনার প্রয়োজন অনুসারে করতে পারে।

$ script "ed    it" "cat/dog"  33.2  \D  

  echo "-------- Either use 'indirect reference'"
  for ((i=1;i<=${#@};i++)) ;do
    #  eval echo \"\$$i\" ..works, but as *pepoluan* 
    #    has pointed out: echo "${!i}" ..is better.
    echo "${!i}"
  done
  echo "-------- OR use an array"
  array=("$@")
  for ((i=0;i<${#array[@]};i++)) ;do
    echo "${array[$i]}" 
  done
  echo "-------- OR use 'set'"
  set  "$@"
  echo "$1"
  echo "$2"
  echo "$3"
  echo "$4"

আউটপুট

  -------- Either use 'indirect reference'
  ed    it
  cat/dog
  33.2
  D
  -------- OR use an array
  ed    it
  cat/dog
  33.2
  D
  -------- OR use 'set'
  ed    it
  cat/dog
  33.2
  D

set এটি অনুসরণ করে যা কিছু কাজ করে, create 1, $ 2 .. ইত্যাদি তৈরি করে This এটি অবশ্যই মূল মানগুলিকে ওভাররাইড করে, তাই কেবল সচেতন থাকুন।


আহ ... সুতরাং 'ইওল' দ্বারা আপনি অপ্রত্যক্ষ রেফারেন্স বোঝাতে চেয়েছিলেন ... $ {! var} কনস্ট্রাক্টটি নিরাপদ, যেমনটি আমি আমার উত্তরে লিখেছিলাম
পেপলুয়ান

@ পেপলুয়ান ... আমাকে সে সম্পর্কে সতর্ক করার জন্য ধন্যবাদ এটি লিখতে অনেক সহজ ... (আমি এখন উল্লিখিত ওয়েবপৃষ্ঠায় ফিরে এসেছি, আমি যদি আরও পড়তে থাকি তবে আমিও সেখানে এটি উল্লেখ করতে
পারতাম

হেহ। তবে যদি
দিকনির্দেশটি

@ পিওপ্লুয়ান ... ঠিক আছে, এটি নির্দেশ করার জন্য ধন্যবাদ ... এবং ঠিক একপাশে: আমি বুঝতে পারছি না কারও কারও evalদ্বারা এটি কেন বিবেচিত হয় evil... (সম্ভবত এটি বানানের কারণে :) ... যদি eval"খারাপ" হয় তবে $ {! Var} সমানভাবে "খারাপ"? ... আমার কাছে এটি কেবল ভাষার একটি অংশ এবং একটি দরকারী অংশ ... তবে আমি অবশ্যই
prefer

1

দ্রষ্টব্য আমি ফাইলের নামগুলিতে ফাঁকা স্থান সমর্থন করি।

function SplitFilePath {
    IFS=$'/' eval "${1}"=\( \${2} \)
}
function JoinFilePath {
    IFS=$'/' eval echo -n \"\${*}\"
    [ $# -eq 1 -a "${1}" = "" ] && echo -n "/"
}
function path_common {
    set -- "${@//\/\///}"       ## Replace all '//' with '/'
    local -a Path1
    local -i Cnt=0
    SplitFilePath Path1 "${1}"
    IFS=$'/' eval set -- \${2} 
    for CName in "${Path1[@]}" ; do
        [ "${CName}" != "${1}" ] && break;
        shift && (( Cnt++ ))
    done
    JoinFilePath "${Path1[@]:0:${Cnt}}"
}

আমি ফাঁকা জায়গাগুলির ফাইল নামগুলির জন্য একটি পরীক্ষার কেস যুক্ত করেছি এবং 2 টি পরীক্ষা স্থির করেছিলাম যা একটি শীর্ষস্থানীয় /

    do_test () {

  if test "${@}"; then echo 0; else echo $? "$@"; failed=$(($failed+1)); fi
}

run_tests () {
  function_to_test=$1; shift
  failed=0
  do_test "$($function_to_test /a/b/c/d /a/b/e/f; echo x)" = /a/bx
  do_test "$($function_to_test /long/names/foo /long/names/bar; echo x)" = /long/namesx
  do_test "$($function_to_test / /a/b/c; echo x)" = /x      
  do_test "$($function_to_test a/b/c/d a/b/e/f ; echo x)" = a/bx
  do_test "$($function_to_test ./a/b/c/d ./a/b/e/f; echo x)" = ./a/bx
  do_test "$($function_to_test '
/
/
' '
/
'; echo x)" = '
/
'x
  do_test "$($function_to_test --/-- --; echo x)" = '--x'
  do_test "$($function_to_test '' ''; echo x)" = x
  do_test "$($function_to_test /foo/bar ''; echo x)" = x
  do_test "$($function_to_test /foo /fo; echo x)" = /x      ## Changed from x
  do_test "$($function_to_test '--$`\! *@ \a\b\e\E\f\r\t\v\\\"'\'' 
' '--$`\! *@ \a\b\e\E\f\r\t\v\\\"'\'' 
'; echo x)" = '--$`\! *@ \a\b\e\E\f\r\t\v\\\"'\'' 
'x
  do_test "$($function_to_test /foo/bar //foo//bar//baz; echo x)" = /foo/barx
  do_test "$($function_to_test foo foo; echo x)" = foox
  do_test "$($function_to_test /fo /foo; echo x)" = /x          ## Changed from x
  do_test "$($function_to_test "/fo d/fo" "/fo d/foo"; echo x)" = "/fo dx"

  if [ $failed -ne 0 ]; then echo $failed failures; return 1; fi
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.