Managing and Using Arrays in Shell Scripts (page 4)

botond published 2019. 03. 11., h - 17:11 time

4. page content

 

Continuation

Az previous page we have become acquainted with associative arrays, now we continue with some solutions that are generally applicable to each type of array.

 

 

Export Arrays

A a Bash does not currently support exporting arrays, so we may need our own solution to access previously declared arrays from other scripts, for example.

First, let's see what happens when we export an array and a regular variable from the command line:

declare -A tomb=([elso]="első" [masodik]="második elem")
valtozo="Sima string változó"

export tomb
export valtozo

Then if we run it export command:

export

then here is our string variable and even our array because we are in the same namespace:

[...]
declare -Ax tomb=([elso]="első" [masodik]="második elem" )
declare -x valtozo="Sima string változó"

This is good so far, but if we run the export command in a shell script:

1
2
3
#!/bin/bash
 
export
[...]
declare -x valtozo="Sima string változó"

Then our array disappears from the list, and only the plain variable "survived" the export, because when the script runs normally, it runs in a sub-shell, and only our normal variable is no longer transferred to its namespace.

However, if we do not run this script as usual, we will source "." use:

. ./scriptfile_neve
[...]
declare -Ax tomb=([elso]="első" [masodik]="második elem" )
declare -x valtozo="Sima string változó"

Then we "get" the array again. This is because when sourceing, the script does not run in a sub-shell, but in the same shell and its namespace from which the source was executed, i.e. in the present case in the command line where we declared and exported the array and the smooth variable. Therefore, the variables created are included in the export. For example, various startup files, such as .bash_profile, .bashrc, etc too.

So, based on what we have said so far, it's normal name -> value based variables can be exported to the global namespace, which can then be accessed in the sub-shell, but arrays cannot be exported, they can only be accessed while remaining in the own namespace.

And sometimes it may be necessary to be able to access an existing array in a run shell script as well. For example, what the .bash_profile or even from the command line. There are some solutions to this, one of which we will try now.

We create two scripts to make the test more convenient. We’re going to start one with sourceing, so it’s like a .bash_profile vagy .bashrc we would have put its contents in our file or even typed it into the command line. The other file will run normally like any other shell script, which will run in a subshell.

Let's say one a.shand the other b.sh

Let’s put two array declarations into the first: An indexed array and an associative array to see both work, and the two rows at the end:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/bash
 
# Indexelt tömb létrehozása
declare -a tomb1=(első második harmadik)
 
# Asszociatív tömb létrehozása
declare -A tomb2=(
    [elso]="Első"
    [masodik]="Második"
    [harmadik]="Harmadik"
)
 
export tomb1_serialized=$(declare -p tomb1)
export tomb2_serialized=$(declare -p tomb2)

Here, the two lines at the end will run the whole thing, doing the following:

A declare -p command returns the declaration line of the specified variable, that is, the command line that can be used to create exactly the same variable. For arrays, including all keys and values. We are actually serializing the array into a string, only here the resulting string output includes the create command itself, which will come in handy anyway.

For example, with our previously created array, this would output:

declare -Ax tomb=([elso]="első" [masodik]="második elem" )

This is good here now because we run rows on the arrays, which can be stored in a plain string variable. This output is read into another variable by a $ () wrapper, which can already be exported as a string. We do all this based on the above theories that only normal variables can be exported to the global namespace, that is, to the namespace of our command line, while arrays cannot.

If you now use "." let's source our file above:

. ./a.sh

Then the declarations and exports in it will also run in the namespace of the run location. So if we release one now export command,

export

you will see the following at the end of the list:

[...]
declare -Ax tomb=([elso]="első" [masodik]="második elem" )
declare -x tomb1_serialized="declare -a tomb1=([0]=\"első\" [1]=\"második\" [2]=\"harmadik\")"
declare -x tomb2_serialized="declare -A tomb2=([elso]=\"Első\" [masodik]=\"Második\" [harmadik]=\"Harmadik\" )"
declare -x valtozo="Sima string változó"

Here you will find the variables "tomb" and "variable" created above, but most importantly we have our two new serialized arrays, which have all the keys and values, and the quotes are pretty much escaped. so they are ready to be transported as a string, for use.

 

 

Interestingly, if we run a file that only contained an export command, we will see the following:

[...]
declare -x tomb1_serialized="declare -a tomb1=([0]=\"első\" [1]=\"második\" [2]=\"harmadik\")"
declare -x tomb2_serialized="declare -A tomb2=([elso]=\"Első\" [masodik]=\"Második\" [harmadik]=\"Harmadik\" )"
declare -x valtozo="Sima string változó"

Exactly what we expected: Our array declaration has disappeared and the three string-based shuffle declarations have been retained.

So, based on these, we compile our other script, called "b.sh", and insert the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/bin/bash
 
eval $tomb1_serialized
eval $tomb2_serialized
 
 
# Innentől már tudjuk használni az eredeti tömb változóinkat.
 
echo "tomb1 indexelt tömb kilistázása:"
for i in "${!tomb1[@]}"; do
    echo "$i: ${tomb1[$i]}"
done
 
echo
echo "tomb2 asszociatív tömb kilistázása:"
for i in "${!tomb2[@]}"; do
    echo "$i: ${tomb2[$i]}"
done

We make the chmod + x then execute. And in the output we get:

tomb1 indexelt tömb kilistázása:
0: első
1: második
2: harmadik

tomb2 asszociatív tömb kilistázása:
elso: Első
masodik: Második
harmadik: Harmadik

This way, we can use the array variables previously created in the global namespace in our executed shell scripts.

Using the eval command carries a security risk because it executes data from outside (from the variable namespace) as a command. Therefore, use it only where you are aware of the machine's circumstances and avoid using it as root. If you need more security, you should build your own serialization and recovery algorithm to replace the eval command.

 

Conclusion

In this long description, we are introduced to the arrays used in shell scripts and how to handle them. As we can see, Bash arrays can be used for pretty much anything to create more flexible scripts. In addition to these, of course, much more could be written about arrays, so I tried to gather the most important parts that we can use in everyday programming. I hope we have been able to put together a usable description that can help those who are now studying this topic.

 

 

 

Navigation

This description consists of several pages: