Accessing array elements in shell - arrays

I have an array as:
Option[0]=$3
Option[1]=$4
Option[2]=$5
Option[3]=$6
Option[4]=$7
Option[5]=$8
I have to access array elements in shell script.
I know the format is "${Option[0]}" but this format is not accepted in my system.
Its giving me error "Bad substitution".

I have found the solution as:
Arrays are not possible in Busybox shell but a tweak is possible like:
Option="$3; $4; $5; $6; $7; $8"
I have used ; because some of the elements were having "space in the string". Like $3 = " Hello World"
And while iterating the array, delimeter was a space itself.
So to modify the delimiter ; was used.
For iterating the above array:
IFS=$';'
for opt in $Option
do
if [ $opt != " " ]; then
echo "$opt"
fi
done

Related

bad array subscript error in associative array

I am trying to create a dictionary program in Bash with the following options : 1. Add a word
2. Update meaning
3. Print dictionary
4. Search a word
5. Search by keyword
For the same, I am creating 2 associative arrays, 1 to store the word - meaning and other to store words-keyword.
The problem is I am not able to store values in the array. Everytime I try to do it, it gives me an error
dict[$word]: bad array subscript
Here is the code for part 1
echo
echo -n "Enter a word : "
read $word
echo
echo -n "Enter it's meaning : "
read $meaning
echo
echo -n "Enter some keywords(with space in between) to describe the word : "
read $keyword
dict[$word]=$meaning
keywords[$word]=$keyword
;;
I also tried inserting the following code to remove new line as suggested in some posts but ended up with same result.
word=`echo $word | grep -s '\n'`
keyword=`echo $keyword | grep -s '\n'`
Have also tried the following way :
dict["$word"]="$meaning"
keywords["$word"]="$keyword"
;;
Output :
dict[$word]: bad array subscript
When reading a variable you preface the variable name with a $ (or wrap in $( and )).
When assigning a value to a variable you do not preface the variable name with a $.
In your example your 3x echo/read sessions are attempting to assign values to your variables, but you've prefaced your variables with $, which means your variables are not getting set as you expect; this in turn could be generating your error because $word is not set/defined (depends on version of bash).
You should be able to see what I mean with the following code snippet:
unset word
echo
echo -n "Enter a word : "
read $word
echo ".${word}."
What do you get as ouput? .. ? .<whatever_you_typed_in>. ?
You may also have a problem with your associative arrays (depending on bash version); as George has mentioned, you should play it safe and explicitly declare your associative arrays.
I would suggest editing your input script like such (remove leading $ on your read variables; explicitly declaring your associative arrays):
echo
echo -n "Enter a word : "
read word
echo
echo -n "Enter it's meaning : "
read meaning
echo
echo -n "Enter some keywords(with space in between) to describe the word : "
read keyword
# print some debug messages:
echo "word=.${word}."
echo "meaning=.${meaning}."
echo "keyword=.${keyword}."
# declare arrays as associative
declare -A dict keywords
# assign values to arrays
dict[$word]=$meaning
keywords[$word]=$keyword
# verify array indexes and values
echo "dict index(es) : ${!dict[#]}"
echo "dict value(s) : ${dict[#]}"
echo "keywords index(es): ${!keywords[#]}"
echo "keywords value(s) : ${keywords[#]}"
In my bash 4.4 , this is not raising any error but is not working correctly either:
$ w="one";m="two";d["$w"]="$m";declare -p d
declare -a d=([0]="two")
It is obvious that bash determines array d as a normal array and not as an associative array.
On the contrary, this one works fine:
$ w="one";m="two";declare -A d;d["$w"]="$m";declare -p d
declare -A d=([one]="two" )
According to bash manual, you need first to declare -A an array in order to be used as an associative one.

Bash How can I use read command to assign multiple words to 1 variable

I am trying to get multiple words/arguments into one variable with read. I tried assigning it into an array and using while loop to put all the elements in the array into 1 string.
read -a info
i=0
datastring=""
while [ $i -lt ${info[#]} ]
do
datastring=$datastring${info[i]}
done
echo "$dataString"
When I run the program it just doesn't do anything and sits there and won't print out datastring and I'm kinda lost on any other way to do it.
read datastring <<<"this sentence contains multiple words"
echo "$datastring"
If you already have an array
datastring=${info[*]}
Will concatenate the array into a single word, using the 1st char of $IFS as a separator. If you want the words all smushed together with no separators, you could do this:
datastring=""
for word in "${info[#]}"; do datastring+=$word; done
or this:
datastring=$(IFS=""; echo "${info[*]}")
or this:
datastring=${info[*]}
datastring=${datastring// /}
Note, all quotes and array indices (* vs #) have been carefully chosen: see
http://www.gnu.org/software/bash/manual/bashref.html#Shell-Parameter-Expansion and
http://www.gnu.org/software/bash/manual/bashref.html#Arrays

Space Delimiter Arrays Shell Script

Array is taking "space" as default delimiter:
str="HI I GOT;IT"
arr2=$(echo $str | tr ";" " ")
for x in $arr2
do
echo " $x"
done
Output:
HI
I
GOT
IT
I want the output to be:
HI I GOT
IT
You haven't said which shell this is, but it looks like bash, so I'll go ith that. This is a job for IFS, which determines how bash splits words. Here we set it to ; for a single command, to split up your string.
You also need to iterate over the array properly (using quotes and [#]) so that it's not split again by bash at this point.
str="HI I GOT;IT"
IFS=\; arr=($str)
for x in "${arr[#]}"
do
echo "$x"
done

how perl array works $"

I am confused about the outcome of this code.
my #lines;
for (my $count = 0; $count < 3; $count++) {
print "Give me input again ";
chomp (my $line = <STDIN>);
$lines[$count] = $line;
}
$" = "|";
print "#lines\n";
When I run the code, how does this: $" = "|"; work?
The results are One|Two|Three. How does the code work so that it puts "|" between each input?
It's simply what interpolation of arrays into double-quoted strings does.
"$foo\n"
is identical to
$foo . "\n"
and
"#lines\n"
is identical to
join($", #lines) . "\n"
This is documented in perldata and in perlvar.
$" is just a special variable name in perl that tells the interpreter how to separate array elements in double-quoted string context. The default value is a space, but the above code tells perl to use | instead. Hence One|Two|Three instead of the default of One Two Three if you left out that line.
See http://perldoc.perl.org/perlvar.html#General-Variables for more detail.

How to print 'AND' between array elements?

If I have an array with name like below.
How do I print "Hi joe and jack and john"?
The algorithm should also work, when there is only one name in the array.
#!/usr/bin/perl
use warnings;
use strict;
my #a = qw /joe jack john/;
my $mesg = "Hi ";
foreach my $name (#a) {
if ($#a == 0) {
$mesg .= $name;
} else {
$mesg .= " and " . $name;
}
}
print $mesg;
Usually we use an array join method to accomplish this. Here pseudo code:
#array = qw[name1 name2 name2];
print "Hey ", join(" and ", #array), ".";
Untested:
{ local $, = " and "; print "Hi "; print #a; }
Just use the special variable $".
$"="and"; #" (this last double quote is to help the syntax coloring)
$mesg="Hi #a";
To collect the perldoc perlvar answers, you may do one of (at least) two things.
1) Set $" (list separator):
When an array or an array slice is interpolated into a double-quoted
string or a similar context such as /.../ , its elements are separated
by this value. Default is a space. For example, this:
print "The array is: #array\n";
is equivalent to this:
print "The array is: " . join($", #array) . "\n";
=> $" affects the behavior of the interpolation of the array into a string
2) Set $, (output field separator):
The output field separator for the print operator. If defined, this
value is printed between each of print's arguments. Default is undef.
Mnemonic: what is printed when there is a "," in your print statement.
=> $, affects the behavior of the print statement.
Either will work, and either may be used with local to set the value of the special variable only within an enclosing scope. I guess the difference is that with $" you are not limited to the print command:
my #z = qw/ a b c /;
local $" = " and ";
my $line = "#z";
print $line;
here the "magic" happens on the 3rd line not at the print command.
In truth though, using join is the most readable, and unless you use a small enclosing block, a future reader might not notice the setting of a magic variable (say nearer the top) and never see that the behavior is not what is expected vs normal performance. I would save these tricks for small one-offs and one-liners and use the readable join for production code.

Resources