web-dev-qa-db-ja.com

bashの配列の配列

ピリオドで区切られたフィールドを含む行ごとに入力ファイルを読み取ろうとしています。それらを後でループできるように、配列の配列に入れたいです。入力は問題ないように見えますが、配列(inData)に「プッシュ」しても機能していないようです。

コードは次のとおりです。

Input file: 
GSDB.GOSALESDW_DIST_INVENTORY_FACT.MONTH_KEY
GSDB.GOSALESDW_DIST_INVENTORY_FACT.ORGANIZATION_KEY


infile=${1}

OIFS=$IFS
IFS=":"

cat ${infile} | while read line
do
      line=${line//\./:}
      inarray=(${line})
#      echo ${inarray[@]}
#      echo ${#inarray[@]}      
#      echo ${inarray[0]}
#      echo ${inarray[1]}
#      echo ${inarray[2]}

      inData=("${inData[@]}" "${inarray[@]}")
done 
IFS=$OIFS

echo ${#inData[@]}   

for ((i = 0; i < ${#inData[@]}; i++))
do
 echo $i
    for ((j = 0; j < ${#inData[$i][@]}; j++))
    do
       echo ${inData[$i][$j]}
    done
done
34
jaybee

Bashは多次元配列をサポートしていません。試して

array=(a b c d)
echo ${array[1]}
echo ${array[1][3]}
echo ${array[1]exit}

それらをシミュレートする方法については、 Advanced Bash Scripting Guide を参照してください。

21
choroba

Bashのフィールドネストボックスですが、例を参照してください。

#!/bin/bash

# requires bash 4 or later; on macOS, /bin/bash is version 3.x,
# so need to install bash 4 or 5 using e.g. https://brew.sh

declare -a pages

pages[0]='domain.de;de;https'
pages[1]='domain.fr;fr;http'

for page in "${pages[@]}"
do
    # turn e.g. 'domain.de;de;https' into
    # array ['domain.de', 'de', 'https']
    IFS=";" read -r -a arr <<< "${page}"

    site="${arr[0]}"
    lang="${arr[1]}"
    prot="${arr[2]}"
    echo "site : ${site}"
    echo "lang : ${lang}"
    echo "prot : ${prot}"
    echo
done
22
Lukáš Kříž

文字列を「配列」に分割できることを知っている。リストのリストを作成できます。たとえば、DBサーバー内のデータベースのリストのように。

dbServersList=('db001:app001,app002,app003' 'db002:app004,app005' 'dbcentral:central')

# Loop over DB servers
for someDbServer in ${dbServersList[@]}
do
    # delete previous array/list (this is crucial!)
    unset dbNamesList
    # split sub-list if available
    if [[ $someDbServer == *":"* ]]
    then
        # split server name from sub-list
        tmpServerArray=(${someDbServer//:/ })
        someDbServer=${tmpServerArray[0]}
        dbNamesList=${tmpServerArray[1]}
        # make array from simple string
        dbNamesList=(${dbNamesList//,/ })
    fi

    # Info
    echo -e "\n----\n$someDbServer\n--"

    # Loop over databases
    for someDB in ${dbNamesList[@]}
    do
        echo $someDB
    done
done

上記の出力は次のようになります。

----
db001
--
app001
app002
app003

----
db002
--
app004
app005

----
dbcentral
--
central
10
Nux

私はこれに苦労しましたが、不快な妥協案を見つけました。一般に、Bashでデータ構造を使用することを含むソリューションの問題に直面した場合、Pythonなどの別の言語に切り替える必要があります。そのアドバイスを無視して、すぐに進む:

私のユースケースには通常、リストのリスト(または配列の配列)とそれらのループが含まれます。通常、それよりも深くネストすることは望ましくありません。また、ほとんどの配列は文字列であり、スペースを含む場合と含まない場合がありますが、通常は特殊文字を含みません。これにより、混乱しない構文を使用して外部配列を表現し、文字列に対して通常のbash処理を使用して2番目のリストまたは配列を取得できます。 IFS区切り文字obviに注意する必要があります。

したがって、連想配列を使用すると、次のようなリストのリストを作成できます。

declare -A JOB_LIST=(
   [job1] = "a set of arguments"
   [job2] = "another different list"
   ...
)

これにより、次のように両方の配列を反復処理できます。

for job in "${!JOB_LIST[@]}"; do
  /bin/jobrun ${job[@]}
done

ああ、キーリストの出力(魔法の${!...})は、リストを順番にたどらないことを意味します。したがって、もう1つ必要なハックは、キーの順序を並べ替えることです(重要な場合)。ソート順はあなた次第です。英数字のソートを使用し、aajob1 bbjob3 ccjob6は完全に受け入れられます。

だから

declare -A JOB_LIST=(
   [aajob1] = "a set of arguments"
   [bbjob2] = "another different list"
   ...
)
sorted=($(printf '%s\n' "${!JOB_LIST[@]}"| /bin/sort))
for job in "${sorted[@]}"; do
   for args in "${job[@]}"; do
     echo "Do something with ${arg} in ${job}"
   done
done
3
The Big Baba

連想配列を使用し、キーで::を使用して深さを示します。 ::は属性の埋め込みにも使用できますが、それは別の主題です...

declare -A __myArrayOfArray=([Array1::Var1]="Assignment" [Array2::Var1]="Assignment")

Array1の下の配列

__myArrayOfArray[Array1::SubArray1::Var1]="Assignment"

任意の配列のエントリは、...によって(順番に)取得できます...

local __sortedKeys=`echo ${!__myArrayOfArray[@]} | xargs -n1 | sort -u | xargs`
for __key in ${__sortedKeys}; do
    #
    # show all properties in the Subordinate Profile "Array1::SubArray1::"
    if [[ ${__key} =~ ^Array1::SubArray1:: ]]; then
        __property=${__key##Array1::SubArray1::}
        if [[ ${__property} =~ :: ]]; then
            echo "Property ${__property%%:*} is a Subordinate array"
        else
            echo "Property ${__property} is set to: ${__myArrayOfArray[${__key}]}"
        fi
    fi 
done

下位の「プロファイル」のリストは、次の方法で導出できます。

declare -A __subordinateProfiles=()
local __profile
local __key
for __key in "${!__myArrayOfArray[@]}"; do
    if [[ $__key =~ :: ]]; then
        local __property=${__key##*:}
        __profile=${__key%%:*}
        __subordinateProfiles[${__profile}]=1
    fi   
done
1
oobash

次のスクリプトのように、配列の(逆)参照を使用できます。

#!/bin/bash

OFS=$IFS     # store field separator
IFS="${2: }" # define field separator
file=$1      # input file name

unset a      # reference to line array
unset i j    # index
unset m n    # dimension

### input

i=0
while read line
do
  a=A$i
  unset $a
  declare -a $a='($line)'
  i=$((i+1))
done < $file
# store number of lines
m=$i

### output

for ((i=0; i < $m; i++))
do
  a=A$i
  # get line size
  # double escape '\\' for sub Shell '``' and 'echo'
  n=`eval echo \\${#$a[@]}`
  for (( j = 0; j < $n; j++))
  do
    # get field value
    f=`eval echo \\${$a[$j]}`
    # do something
    echo "line $((i+1)) field $((j+1)) = '$f'"
  done
done

IFS=$OFS

https://unix.stackexchange.com/questions/199348/dynamically-create-array-in-bash-with-variables-as-array-name へのクレジット

0
setempler