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
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 .
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
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
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
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
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