ভেরিয়েবলটি শেলের মতো বোর্নে একটি অ্যারে হয়?


14

বোর্নে শেলের মতো যা অ্যারে ভেরিয়েবল সমর্থন করে আমরা ভ্যারিয়েবল অ্যারে কিনা তা পরীক্ষা করতে কিছু পার্সিং ব্যবহার করতে পারি।

নীচে সমস্ত কমান্ড চলমান পরে চালানো হয়েছিল a=(1 2 3)

zsh:

$ declare -p a
typeset -a a
a=( 1 2 3 )

bash:

$ declare -p a
declare -a a='([0]="1" [1]="2" [2]="3")'

ksh93:

$ typeset -p a
typeset -a a=(1 2 3)

pdksh এবং এর ডেরাইভেটিভ:

$ typeset -p a
set -A a
typeset a[0]=1
typeset a[1]=2
typeset a[2]=3

yash:

$ typeset -p a
a=('1' '2' '3')
typeset a

এর একটি উদাহরণ bash:

if declare -p var 2>/dev/null | grep -q 'declare -a'; then
  echo array variable
fi

এই পদ্ধতির খুব বেশি কাজ এবং একটি সাব-শেল স্প্যান করা প্রয়োজন। মত অন্যান্য শেল builtin ব্যবহার =~মধ্যে [[ ... ]]একটি subshell প্রয়োজন হবে না, কিন্তু এখনও খুব বেশি জটিল।

এই কাজটি সম্পাদন করার সহজ উপায় কি আছে?


কোন পরিস্থিতিতে আপনার ভেরিয়েবলগুলি অ্যারে রয়েছে কিনা তা যাচাই করা দরকার?
কুসালানন্দ

উত্তর:


10

আমি মনে করি না আপনি পারবেন, এবং আমি মনে করি না এটি আসলে কোনও পার্থক্য করে।

unset a
a=x
echo "${a[0]-not array}"

x

যে উভয় একই জিনিস করে ksh93এবং bash। দেখে মনে হচ্ছে সম্ভবত সমস্ত ভেরিয়েবলগুলি সেই শেলগুলিতে অ্যারে, বা কমপক্ষে কোনও নিয়মিত ভেরিয়েবল যা বিশেষ বৈশিষ্ট্য বরাদ্দ করা হয়নি, তবে আমি এর বেশি পরীক্ষা করিনি check

bashবনাম একটি স্ট্রিং পরিবর্তনশীল একটি অ্যারের জন্য বিভিন্ন আচরণে সম্পর্কে ম্যানুয়াল আলোচনা যখন ব্যবহার +=বরাদ্দকরণ, কিন্তু এটা পরে হেজেস এবং রাজ্যের অ্যারের শুধুমাত্র ভিন্নভাবে একটি আচরণ করে যৌগ নিয়োগ প্রসঙ্গে।

এটি আরও উল্লেখ করে যে কোনও ভেরিয়েবলকে একটি অ্যারে হিসাবে বিবেচনা করা হয় যদি কোনও সাবস্ক্রিপ্টকে একটি মূল্য নির্ধারিত করা হয় - এবং স্পষ্টভাবে নাল-স্ট্রিংয়ের সম্ভাবনা অন্তর্ভুক্ত করে। উপরে আপনি দেখতে পাচ্ছেন যে একটি নিয়মিত নিয়োগের ফলে সাবস্ক্রিপ্ট নির্ধারিত হওয়ার ফলস্বরূপ - এবং তাই আমি অনুমান করি যে সমস্ত কিছু অ্যারে ray

ব্যবহারিকভাবে, সম্ভবত আপনি ব্যবহার করতে পারেন:

[ 1 = "${a[0]+${#a[@]}}" ] && echo not array

... পরিষ্কারভাবে সেট ভেরিয়েবলগুলি নির্দিষ্ট করতে যা কেবলমাত্র 0 মানের একটি একক সাবস্ক্রিপ্ট বরাদ্দ করা হয়েছে।


সুতরাং আমি ${a[1]-not array}কাজটি করতে পারি কিনা তা পরীক্ষা করে অনুমান করি, তাই না?
cuonglm

@cuonglm - ঠিক আছে, bashম্যানুয়াল অনুসারে নয় : সাবস্ক্রিপ্টের কোনও মূল্য নির্ধারিত হলে একটি অ্যারে ভেরিয়েবল সেট হিসাবে বিবেচিত হবে। নাল স্ট্রিং একটি বৈধ মান। যদি কোনও সাবস্ক্রিপ্ট নির্দিষ্ট করা হয় তবে এটির জন্য একটি অ্যারে নির্দিষ্ট করা আছে। অনুশীলনে, নাও, কারণ আপনি করতে পারেন a[5]=x। আমার ধারণা [ 1 -eq "${#a[@]}" ] && [ -n "${a[0]+1}" ]কাজ করতে পারে।
মাইকসার্ভ

6

সুতরাং আপনি কার্যকরভাবে declare -pএটির চারপাশের আবর্জনা ছাড়াই কেবল মাঝের অংশটি চান ?

আপনি যেমন ম্যাক্রো লিখতে পারেন:

readonly VARTYPE='{ read __; 
       case "`declare -p "$__"`" in
            "declare -a"*) echo array;; 
            "declare -A"*) echo hash;; 
            "declare -- "*) echo scalar;; 
       esac; 
         } <<<'

যাতে আপনি করতে পারেন:

a=scalar
b=( array ) 
declare -A c; c[hashKey]=hashValue;
######################################
eval "$VARTYPE" a #scalar
eval "$VARTYPE" b #array
eval "$VARTYPE" c #hash

(আপনি যদি ফাংশন-স্থানীয় ভেরিয়েবলগুলিতে এটি ব্যবহার করতে চান তবে একটি নিছক ফাংশন তা করবে না)।


এলিয়াস সহ

shopt -s expand_aliases
alias vartype='eval "$VARTYPE"'

vartype a #scalar
vartype b #array
vartype c #hash

পছন্দ করুন এলিয়াস এটিকে সুন্দর দেখায়। +1
PSkocik

আমি বলতে চাইছিলাম - alias vartype="$VARTYPE"... বা ঠিক কোনও সংজ্ঞা দিচ্ছে না $VARTYPE- এটি কাজ করা উচিত, তাই না? আপনার কেবল সেই shoptজিনিসটির প্রয়োজন bashহবে কারণ এটি aliasস্ক্রিপ্টগুলিতে সম্প্রসারণ সম্পর্কিত অনুমানের সাথে ভেঙে যায় ।
মাইকসার্ভ

1
@ মেকজারভেল আমি নিশ্চিত যে কুইংলম তার প্রয়োজন এবং পছন্দগুলি সম্পর্কে এই পদ্ধতিটি টুইট করতে সক্ষম is ;-)
পিএসকোকিক

... এবং সুরক্ষা বিবেচনা।
PSkocik

কোনও বিন্দুতে উপরের কোডটি ব্যবহারকারী সরবরাহিত টেক্সট দেয় না। এটি কোনও ফাংশনের চেয়ে কম সুরক্ষিত নয়। আমি আপনাকে ফাংশন কেবলমাত্র পঠনযোগ্য করে তোলার বিষয়ে ঝগড়া করতে দেখিনি, তবে ঠিক আছে, আমি পরিবর্তনশীল পাঠযোগ্যভাবে চিহ্নিত করতে পারি।
PSkocik

6

Zsh এ

zsh% a=(1 2 3) s=1
zsh% [[ ${(t)a} == *array* ]] && echo array
array
zsh% [[ ${(t)s} == *array* ]] && echo array
zsh%

সম্ভবত echo ${(t)var}সহজ। এর জন্য ধন্যবাদ.

4

সাথে ভেরিয়েবল ভেরি পরীক্ষা করতে

b=("${!var[@]}")
c="${#b[@]}"

একাধিক অ্যারে সূচক থাকলে পরীক্ষা করা সম্ভব:

[[ $c > 1 ]] && echo "Var is an array"

প্রথম সূচকের মানটি যদি শূন্য না হয়:

[[ ${b[0]} -eq 0 ]] && echo "Var is an array"      ## should be 1 for zsh.

একমাত্র শক্ত বিভ্রান্তি তখন হয় যখন কেবলমাত্র একটি সূচক মান থাকে এবং সেই মানটি শূন্য (বা একটি) one

এই অবস্থার জন্য, অ্যারে নয় এমন একটি ভেরিয়েবল থেকে অ্যারে উপাদান সরানোর চেষ্টা করার একটি পার্শ্ব প্রতিক্রিয়া ব্যবহার করা সম্ভব:

**bash** reports an error with             unset var[0]
bash: unset: var: not an array variable

**zsh** also reports an error with         $ var[1]=()
attempt to assign array value to non-array

এটি ব্যাশের জন্য সঠিকভাবে কাজ করে:

# Test if the value at index 0 could be unset.
# If it fails, the variable is not an array.
( unset "var[0]" 2>/dev/null; ) && echo "var is an array."

Zsh এর জন্য সূচকটি 1 হতে পারে (যদি না কোনও সামঞ্জস্যপূর্ণ মোড সক্রিয় থাকে)।

ভেরার 0 সূচক মুছে ফেলার পার্শ্ব প্রতিক্রিয়া এড়াতে সাব-শেলটি প্রয়োজন।

এটিকে কাজ করার জন্য আমি কোনও উপায় খুঁজে পাইনি।

সম্পাদনা 1

এই ফাংশনটি কেবল bash4.2 + এ কাজ করে

getVarType(){
    varname=$1;
    case "$(typeset -p "$varname")" in
        "declare -a"*|"typeset -a"*)    echo array; ;;
        "declare -A"*|"typeset -A"*)    echo hash; ;;
        "declare -- "*|"typeset "$varname*| $varname=*) echo scalar; ;;
    esac;
}

var=( foo bar );  getVarType var

সম্পাদনা 2

এটি কেবল bash4.2 + এর জন্যও কাজ করে

{ typeset -p var | grep -qP '(declare|typeset) -a'; } && echo "var is an array"

দ্রষ্টব্য: ভের পরীক্ষিত স্ট্রিংগুলি অন্তর্ভুক্ত করা হলে এটি মিথ্যা ধনাত্মকতা দেবে।


শূন্য উপাদানগুলির সাথে অ্যারে সম্পর্কে কীভাবে?
cuonglm

1
ডেটা সম্পাদনা, থো। দেখতে খুব আসল দেখাচ্ছে। : ডি
পিএসকোকিক

@cuonglm ( unset "var[0]" 2>/dev/null; ) && echo "var is an array."যখন সঠিকভাবে var=()শূন্য উপাদানগুলির সাথে অ্যারেতে সেট করা থাকে তখন চেকটি সঠিকভাবে প্রতিবেদন করে var এটি ঘোষণার জন্য ঠিক সমান কাজ করে।

স্কেলারের জন্য পরীক্ষাটি কার্যকর হবে না যদি স্কেলারটি রফতানি করা হয় বা পূর্ণসংখ্যার / ছোট হাত / পঠনযোগ্য চিহ্নিত করা হয় ... আপনি সম্ভবত নিরাপদে এটি তৈরি করতে পারেন যে অন্য কোনও খালি খালি আউটপুট মানে স্কেলার ভেরিয়েবল। আমি জিএনইউ গ্রেপের উপর নির্ভরতা এড়াতে grep -Eপরিবর্তে ব্যবহার করব grep -P
স্টাফেন চেজেলাস

@ পূর্ণসংখ্যা এবং / অথবা ছোট হাতের অক্ষর ব্যবহার সঙ্গে স্কালে জন্য StéphaneChazelas পরীক্ষা (ব্যাশ মধ্যে) এবং / অথবা কেবলমাত্র সবসময় দিয়ে শুরু -aকরুন, এরকম: declare -airl var='()'। সুতরাং গ্রেপ পরীক্ষা কাজ করবে ।

3

জন্য ব্যাশ , এটি একটি হ্যাক (যদিও নথিভুক্ত) একটি সামান্য বিট আছে: ব্যবহার করার প্রচেষ্টা typeset"অ্যারে" অ্যাট্রিবিউট মুছে ফেলার জন্য:

$ typeset +a BASH_VERSINFO
bash: typeset: BASH_VERSINFO: cannot destroy array variables in this way
echo $?
1

(আপনি zshএটি এতে করতে পারবেন না , এটি আপনাকে কোনও অ্যারেকে একটি স্ক্যালারে রূপান্তর করতে দেয়, এতে bashএটি স্পষ্টভাবে নিষিদ্ধ))

তাই:

 typeset +A myvariable 2>/dev/null || echo is assoc-array
 typeset +a myvariable 2>/dev/null || echo is array

বা কোনও ফাংশনে, শেষের দিকে সতর্কতার সাথে লক্ষ্য করা:

function typeof() {
    local _myvar="$1"
    if ! typeset -p $_myvar 2>/dev/null ; then
        echo no-such
    elif ! typeset -g +A  $_myvar 2>/dev/null ; then
        echo is-assoc-array
    elif ! typeset -g +a  $_myvar 2>/dev/null; then
        echo is-array
    else
        echo scalar
    fi
}

typeset -g(বাশ-৪.২ বা তার পরে) এর ব্যবহারটি নোট করুন , এটি কোনও ফাংশনের মধ্যে প্রয়োজন যাতে typeset(সিনা। declare) localআপনি যে মূল্যটি পরিদর্শন করার চেষ্টা করছেন তার মতো কাজ করতে এবং ক্লোবারটি কাজ না করে । এটি ফাংশন "পরিবর্তনশীল" প্রকারগুলিও পরিচালনা করে না, প্রয়োজনে আপনি অন্য একটি শাখা পরীক্ষা যুক্ত করতে পারেন typeset -f


আর একটি (প্রায় সম্পূর্ণ) বিকল্পটি হ'ল:

    ${!name[*]}
          If name is an array variable, expands to  the  list
          of  array indices (keys) assigned in name.  If name
          is not an array, expands to 0 if name  is  set  and
          null  otherwise.   When @ is used and the expansion
          appears within double quotes, each key expands to a
          separate word.

যদিও একটি সামান্য সমস্যা আছে, 0 এর একক সাবস্ক্রিপ্ট সহ একটি অ্যারের উপরের শর্তের সাথে দুটি মিলছে। এটি এমন একটি বিষয় যা মাইক্রজারও উল্লেখ করে, ব্যাশের সত্যই কোনও শক্ত তাত্পর্য নেই এবং এর মধ্যে কিছু (যদি আপনি চেঞ্জলগটি পরীক্ষা করেন) কেএসএস এবং দায়ের করা যায় কীভাবে ${name[*]}বা তার সাথে তুলনামূলকভাবে${name[@]} আচরণ একটি অ-বিন্যাস করুন।

সুতরাং একটি আংশিক সমাধান হ'ল:

if [[ ${!BASH_VERSINFO[*]} == '' ]]; then
    echo no-such
elif [[ ${!BASH_VERSINFO[*]} == '0' ]]; then 
    echo not-array
elif [[ ${!BASH_VERSINFO[*]} != '0' ]]; 
    echo is-array    
fi

আমি অতীতে এই বিষয়ে একটি প্রকরণ ব্যবহার করেছি:

while read _line; do
   if [[ $_line =~ ^"declare -a" ]]; then 
     ...
   fi 
done < <( declare -p )

এটিরও যদিও সাব-শেল দরকার।

আরও একটি সম্ভবত কার্যকর কৌশল হ'ল compgen:

compgen -A arrayvar

এটি সমস্ত সূচিকৃত অ্যারে তালিকাভুক্ত করবে, তবে সহযোগী অ্যারেগুলি বিশেষভাবে পরিচালনা করা হয় না (বাশ -4.4 অবধি) এবং নিয়মিত ভেরিয়েবল হিসাবে প্রদর্শিত হবে ( compgen -A variable)


typeset +aএছাড়াও ksh একটি ত্রুটি রিপোর্ট। যদিও zsh এ নেই।

1

সংক্ষিপ্ত উত্তর:

দুটি শেলের জন্য যা এই স্বরলিপিটি প্রবর্তন করেছে ( bashএবং ksh93) একটি স্কেলার ভেরিয়েবল কেবল একটি একক উপাদান সহ একটি অ্যারে

অ্যারে তৈরি করার জন্যও বিশেষ ঘোষণার দরকার নেই । কেবলমাত্র অ্যাসাইনমেন্ট যথেষ্ট, এবং একটি সরল অ্যাসাইনমেন্টের var=valueসাথে সমান var[0]=value


চেষ্টা করুন: bash -c 'unset var; var=foo; typeset -p var'। বাশ উত্তরের একটি অ্যারে রিপোর্ট করে (একটি -a প্রয়োজন) ?. এখন সঙ্গে তুলনা: bash -c 'unset var; var[12]=foo; typeset -p var'। কেন পার্থক্য আছে ?. উত্তর: শেলটি একটি ধারণা বজায় রাখে (ভাল বা খারাপের জন্য) যার মধ্যে ভারগুলি স্ক্যালার বা অ্যারে হয়। শেল ksh উভয় ধারণাকে একটিতে মিশ্রিত করে।

1

ইয়াশের arrayবিল্টিনে কিছু বিকল্প রয়েছে যা কেবল অ্যারে ভেরিয়েবলগুলির সাথে কাজ করে। উদাহরণ: -dবিকল্পটি অ-অ্যারে ভেরিয়েবলের ক্ষেত্রে ত্রুটির প্রতিবেদন করবে:

$ a=123
$ array -d a
array: no such array $a

সুতরাং আমরা এর মতো কিছু করতে পারি:

is_array() (
  array -d -- "$1"
) >/dev/null 2>&1

a=(1 2 3)
if is_array a; then
  echo array
fi

b=123
if ! is_array b; then
  echo not array
fi

অ্যারে ভেরিয়েবলটি কেবল পঠনযোগ্য হলে এই পদ্ধতির কাজ হবে না । একটি ত্রুটি বাড়ে যা কেবল পঠনযোগ্য ভেরিয়েবলকে সংশোধন করার চেষ্টা করছে :

$ a=()
$ readonly a
$ array -d a
array: $a is read-only

0
#!/bin/bash

var=BASH_SOURCE

[[ "$(declare -pa)" =~ [^[:alpha:]]$var= ]]

case "$?" in 
  0)
      echo "$var is an array variable"
      ;;
  1)
      echo "$var is not an array variable"
      ;;
  *)
      echo "Unknown exit code"
      ;;
esac
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.