I am planning a script to manage some pieces of my Linux systems and am at the point of deciding if I want to use bash or python.
I would prefer to do this as a Bash script simply because the commands are easier, but the real deciding factor is configuration. I need to be able to store a multi-dimensional array in the configuration file to tell the script what to do with itself. Storing simple key=value pairs in config files is easy enough with bash, but the only way I can think of to do a multi-dimensional array is a two layer parsing engine, something like
array=&d1|v1;v2;v3&d2|v1;v2;v3
but the marshall/unmarshall code could get to be a bear and its far from user friendly for the next poor sap that has to administer this. If i can't do this easily in bash i will simply write the configs to an xml file and write the script in python.
Is there an easy way to do this in bash?
thanks everyone.
Expanding on Paul's answer - here's my version of working with associative sub-arrays in bash:
It works with mixed values in the main array - strings/arrays/assoc. arrays
The key here is to wrap the subarrays in single quotes and use
*
instead of@
when storing a subarray inside the main array so it would get stored as a single, space separated string:"${SUB_1[*]}"
Then it makes it easy to parse an array out of that when looping through values with
IFS=' ' read -a val <<< ${MAIN_ARRAY[$key]}
The code above outputs:
Bash doesn't have multi-dimensional array. But you can simulate a somewhat similar effect with associative arrays. The following is an example of associative array pretending to be used as multi-dimensional array:
If you don't declare the array as associative (with
-A
), the above won't work. For example, if you omit thedeclare -A arr
line, theecho
will print2 3
instead of0 1
, because0,0
,1,0
and such will be taken as arithmetic expression and evaluated to0
(the value to the right of the comma operator).I do this using associative arrays since bash 4 and setting
IFS
to a value that can be defined manually.The purpose of this approach is to have arrays as values of associative array keys.
In order to set IFS back to default just unset it.
unset IFS
This is an example:
The output of the script below is:
After a lot of trial and error i actually find the best, clearest and easiest multidimensional array on bash is to use a regular var. Yep.
Advantages: You don't have to loop through a big array, you can just echo "$var" and use grep/awk/sed. It's easy and clear and you can have as many columns as you like.
Example:
If you want to find everyone in peru
Only grep(sed) in the third field
If you only want x field
Everyone in peru that's called thomas and just return his lastname
Any query you can think of... supereasy.
To change an item:
To delete a row that contains "x"
To change another field in the same row based on a value from another item
Of course looping works too if you want to do that
The only gotcha iv'e found with this is that you must always quote the var(in the example; both var and i) or things will look like this
and someone will undoubtedly say it won't work if you have spaces in your input, however that can be fixed by using another delimeter in your input, eg(using an utf8 char now to emphasize that you can choose something your input won't contain, but you can choose whatever ofc):
If you want to store newlines in your input, you could convert the newline to something else before input and convert it back again on output(or don't use bash...). Enjoy!
Bash does not support multidimensional arrays, nor hashes, and it seems that you want a hash that values are arrays. This solution is not very beautiful, a solution with an xml file should be better :