You need to use declare -A
instead of declare -a
. You are clearly using associative arrays with arbitrary string arguments as indices, but declare -a
is only for integer indexed arrays. arg.txt
does not evaluate to a valid integer, hence your error.
Edit
You seem to be using bash
version 3. Unfortunately, associative arrays are not available until version 4. I recommend you post a sanitized version of your original deploy.sh
script with sensitive personal information removed so you can get ideas from other people about alternative approaches.
Edit 2
Just to summarize a bit of exchange in the chat:
The easiest way to do some action over all the arguments is to just iterate over them with a for
loop:
for arg; do
scp login1@host1:"$arg" login2@host2:/dest/
done
Remember to double-quote all instances of "$arg"
.
You do not need to put the arguments in an array yourself, as they already exist in the array $@
, which is what for
uses by default when you don't give an explicit in list...
.
I would be suspicious of your version of Bash to start. I'm on this version and I can set arrays just fine.
$ bash --version
GNU bash, version 4.2.45(1)-release (x86_64-redhat-linux-gnu)
Example
$ array[0]=0
$ array[1]=1
$ array[2]=2
You can then recall them individually:
$ echo ${array[0]}
0
$ echo ${array[1]}
1
$ echo ${array[2]}
2
Or as a list:
$ echo "${array[@]}"
0 1 2
You cannot just call the array as another variable:
$ echo $array
0
I believe this may have been what was misleading you into thinking it wasn't working correctly. Also setting an array element with another variable's value also works.
Example
$ newval=3
$ array[2]=$newval
$ echo "${array[@]}"
0 1 3
You could also use printf
here, doing so will show you why you want to quote the results of ${array[@]}
. But first let's add a string to the array:
$ array[0]="a string"
Without the quotes:
$ printf "%s\n" ${array[@]}
a
string
1
3
With quotes:
$ printf "%s\n" "${array[@]}"
a string
1
3
Passing things around
Well you have 2 tactics that you can make use of within Bash. You can simply set variables so that they're globally scoped. This is often the technique that most people employ.
The other method involves passing by value, values to functions within Bash. I'll show a basic function where I pass it 2 values.
Example
$ function hello() {
printf "I got arg1: %d and arg2: %d\n" $1 $2
}
Now when I execute it with different arguments:
$ hello 1 2
I got arg1: 1 and arg2: 2
$ hello 3 4
I got arg1: 3 and arg2: 4
$ hello 3 blah
bash: printf: blah: invalid number
I got arg1: 3 and arg2: 0
You can read more about arrays and functions within Bash here to get a better understanding of the technologies.
References
Best Answer
Using
readarray
in thebash
shell, and GNUsed
:The built-in
readarray
reads the lines into an array. The lines are read from a process substitution. Thesed
command in the process substitution will only output every second line read frommy_command
(and could also be writtensed '1!n;d'
, or assed -n 'n;p'
with standardsed
).In GNU
sed
, the addressn~m
addresses everym
:th line starting at linen
. This is a GNU extension to standardsed
, for convenience.The
my_command
command will only ever be called once.Testing: