web-dev-qa-db-fra.com

Tableau de tableaux dans bash

J'essaie de lire un fichier d'entrée ligne par ligne qui contient des champs délimités par des points. Je veux les mettre dans un tableau de tableaux afin que je puisse les parcourir plus tard. L'entrée semble être correcte, mais "pousser" cela sur le tableau (inData) ne semble pas fonctionner.

Le code va:

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 ne prend pas en charge les tableaux multidimensionnels. Essayer

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

Pour des astuces sur la façon de les simuler, voir Advanced Bash Scripting Guide .

21
choroba

Nichoir de champ en bash mais il ne peut pas contourner voir l'exemple.

#!/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říž

Sachant que vous pouvez diviser la chaîne en "tableau". Vous pouvez créer une liste de listes. Comme par exemple une liste de bases de données sur des serveurs 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

Le résultat ci-dessus serait:

----
db001
--
app001
app002
app003

----
db002
--
app004
app005

----
dbcentral
--
central
10
Nux

J'ai lutté avec cela, mais j'ai trouvé un compromis inconfortable. En général, face à un problème dont la solution implique l'utilisation de structures de données dans Bash, vous devez basculer vers une autre langue comme Python. Ignorer ces conseils et aller de l'avant:

Mes cas d'utilisation impliquent généralement des listes de listes (ou des tableaux de tableaux) et une boucle sur eux. Vous ne voulez généralement pas nicher beaucoup plus profondément que cela. De plus, la plupart des tableaux sont des chaînes qui peuvent contenir ou non des espaces, mais ne contiennent généralement pas de caractères spéciaux. Cela me permet d'utiliser une syntaxe à ne pas confondre pour exprimer le tableau externe, puis d'utiliser le traitement bash normal sur les chaînes pour obtenir une deuxième liste ou tableau. Vous devrez faire attention à votre délimiteur IFS, obvi.

Ainsi, les tableaux associatifs peuvent me donner un moyen de créer une liste de listes comme:

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

Cela vous permet d'itérer sur les deux tableaux comme:

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

Ah, sauf que la sortie de la liste des clés (en utilisant le magique ${!...}) Signifie que vous ne traverserez pas votre liste dans l'ordre. Par conséquent, un hack supplémentaire est de trier l'ordre des clés, si cela est important pour vous. L'ordre de tri dépend de vous; Je trouve pratique d'utiliser le tri alphanumérique et le recours à aajob1 bbjob3 ccjob6 Est parfaitement acceptable.

Par conséquent

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

J'utilise des tableaux associatifs et utilise :: dans la clé pour indiquer la profondeur. Le :: peut également être utilisé pour incorporer des attributs, mais c'est un autre sujet, ...

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

Un tableau sous Array1

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

Les entrées de n'importe quel tableau peuvent être récupérées (dans l'ordre ...) par ...

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

LA liste des "Profils" subordonnés peut être dérivée par:

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

Vous pouvez utiliser des tableaux de (dé) référencement comme dans ce script:

#!/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

Crédit à https://unix.stackexchange.com/questions/199348/dynamically-create-array-in-bash-with-variables-as-array-name

0
setempler