How to store a continous number in array, bash scripting? - arrays

It is easy to declare and store a number in array but problem is that the user gives input 1234 and i wanted to store this numbers as $array[0]=1, $array[1]=2, $array[2]=3, $array[3]=4 but instead what actually happens is that $array[0]=1234, $array[1]=null, $array[2]=null, $array[3]=null. I don't know how to store each number separately
#!/bin/bash
declare -a key
read -p "Enter the encryption key: " numbers
key=($numbers)
echo ${key[0]}
echo ${key[1]}
echo ${key[2]}
echo ${key[3]}.
Actual output:
Enter the encryption key: 1234
1234
null
null
null
Desired output:
Enter the encryption key: 1234
1
2
3
4
Thank you, in advance :)

There is also a possibility to use
key=(`grep -o . <<< "$numbers"`)
And you can access different letters in $numbers without creating an array by using a substring notation ${string:initial_index:length_of_substring}:
echo ${numbers:0:1}
echo ${numbers:1:1}
echo ${numbers:2:1}
echo ${numbers:3:1}

Seeing how you're using read so you already assume that there are no spaces in the key, you can do this:
#!/bin/bash
declare str
read -p "Enter the encryption key: " str
# replace each character with that character + space
spaced=$(echo "$str" | sed 's/\(.\)/\1 /g')
# without quotes, array elements will be each of the space-separated strings
numbers=( $spaced )
printf "array element %s\n" "${numbers[#]}"
Output:
Enter the encryption key: hello123
array element h
array element e
array element l
array element l
array element o
array element 1
array element 2
array element 3

You can try.
declare -a key
read -p "Enter the encryption key: " numbers
while read -n1 input; do
key+=("$input")
done < <(printf '%s' "$numbers")
printf '%s\n' "${key[#]}"

Related

How to create a for loop that reads each character in ksh

I'm unable to find any for loop syntax that works with ksh for me. I'm wanting to create a program that esentially will add up numbers that are assigned to letters when a user inputs a word into the program. I want the for loop to read the first character, grab the number value of the letter, and then add the value to a variable that starts out equaled to 0. Then the next letter will get added to the variable's value and so on until there are no more letters and there will be a variable from the for loop that equals a value.
I understand I more than likely need an array that specifies what a letter's (a-z) value would be (1-26)...which I am finding difficult to figure that out as well. Or worst case I figure out the for loop and then make about 26 if statements saying something like if the letter equals c, add 3 to the variable.
So far I have this (which is pretty bare bones):
#!/bin/ksh
typeset -A my_array
my_array[a]=1
my_array[b]=2
my_array[c]=3
echo "Enter a word: \c"
read work
for (( i=0; i<${work}; i++ )); do
echo "${work:$i:1}"
done
Pretty sure this for loop is bash and not ksh. And the array returns an error of typeset: bad option(s) (I understand I haven't specified the array in the for loop).
I want the array letters (a, b, c, etc) to correspond to a value such as a = 1, b = 2, c = 3 and so on. For example the word is 'abc' and so it would add 1 + 2 + 3 and the final output will be 6.
You were missing the pound in ${#work}, which expands to 'length of ${work}'.
#!/bin/ksh
typeset -A my_array
my_array[a]=1
my_array[b]=2
my_array[c]=3
read 'work?enter a word: '
for (( i=0; i<${#work}; i++ )); do
c=${work:$i:1} w=${my_array[${work:$i:1}]}
echo "$c: $w"
done
ksh2020 supports read -p PROMPT syntax, which would make this script 100% compatible with bash. ksh93 does not. You could also use printf 'enter a word: ', which works in all three (ksh2020, ksh93, bash) and zsh.
Both ksh2020 and ksh93 understand read var?prompt which I used above.
First check the input work, you only want {a..z}.
charwork=$(tr -cd "[a-z]" <<< "$work")
Next you can fill 2 arrays with corresponding values
a=( {a..z} )
b=( {1..26} )
Using these arrays you can make a file with sed commands
for ((i=0;i<26;i++)); do echo "s/${a[i]}/${b[i]}+/g"; done > replaceletters.sed
# test it
echo "abcz" | sed -f replaceletters.sed
# result: 1+2+3+26+
Before you can pipe this into bc, use sed to remove the last + character.
Append s/+$/\n/ to replaceletters.sed and bc can calculate it.
Now you can use sed for replacing letters by digits and insert + signs.
Combining the steps, you have
a=( {a..z} )
b=( {1..26} )
tr -cd "[a-z]" <<< "$work" |
sed -f <(
for ((i=0;i<26;i++)); do
echo "s/${a[i]}/${b[i]}+/g"
done
echo 's/+$/\n/'
) | bc
In the loop you can use $i and avoid array b, but remember that the array start with 0, so a[5] corresponds with 6.

Bash: Is there a built-in way to get the maximum length of the keys in an associative array

In Bash, given an associative array, how do I find the length of the longest key?
Say, I declare myArray as shown below:
$ declare -A myArray=([zero]=nothing [one]='just one' [multiple]='many many')
$ echo ${myArray[zero]}
nothing
$ echo ${myArray[one]}
just one
$ echo ${myArray[multiple]}
many many
$
I can get it using the below one-liner
$ vSpacePad=`for keys in "${!myArray[#]}"; do echo $keys; done | awk '{print length, $0}' | sort -nr | head -1 | awk '{print $1}'`;
$ echo $vSpacePad
8
$
Am looking for something simpler like below, but unfortunately, these just give the count of items in the array.
$ echo "${#myArray[#]}"
3
$ echo "${#myArray[*]}"
3
You do need to loop over the keys, but you don't need any external tools:
max=-1
for key in "${!myArray[#]}"; do
len=${#key}
((len > max)) && max=$len
done
echo $max # => 8
If you want to print the elements of an array one per line, you don't need a loop: printf is your friend:
printf '%s\n' "${!myArray[#]}"
printf iterates until all the arguments are consumed
Is there a built-in way to get the maximum length of the keys in an associative array
No.
how do I find the length of the longest key?
Iterate over array elements, get the element length and keep the biggest number.
Do not use backticks `. Use $(..) instead.
Quote variable expansions - don't echo $keys, do echo "$keys". Prefer printf to echo.
If array elements do not have newlines and other fishy characters, you could:
printf "%s\n" "${myArray[#]}" | wc -L

Array in Bash: Displaying all elements of array

echo "Enter N " # enter N for number of inputs for the loop
read N # reading the N
#using c-style loop
for((i=1;i<=N;i++))
do
read -a arr # arr is the name of the array
done
echo ${arr[*]} # 1
echo ${arr[#]} # 2
Tried all the ways to display all the elements of the array but not getting the desired output. It's displaying the last element of the array.
To be able to populate an array in loop use:
arr+=("$var")
Full code:
read -p 'Enter N: ' N
arr=() # initialize an array
# loop N times and append into array
for((i=1;i<=N;i++)); do
read a && arr+=("$a")
done
you are reading the data in an array arr and trying to print array
You keep redefining array with read -a. The code should be written like this instead:
#!/bin/bash
echo "Enter N " # enter N for number of inputs for the loop
read N # reading the N
#using c-style loop
declare -a array
for((i=1;i<=N;i++))
do
read array[$i] # arr is the name of the array
done
echo ${array[*]} # 1
echo ${array[#]} # 2
There are probably better ways to doing this. I just wanted to show how to fix your current code.
Example run
$ bash ./dummy.sh
Enter N
2
3
4
3 4
3 4
Hopefully this help other's who have the same issues.
Display all contents of the array in the shell:
"${arr[*]}"
Cleaning up your script (not sure what your intention was, though):
read -p "Enter N " N # User inputs the number of entries for the array
ARR=() # Define empty array
#using c-style loop
for ((i=1;i<=N;i++))
do
read -p "Enter array element number $N: " ADD # Prompt user to add element
ARR+=($ADD) # Actually add the new element to the array.
done
echo "${ARR[*]}" # Display all array contents in a line.
I found a similar solution from #choroba at: How to echo all values from array in bash

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.

Search array for string and return position in unix

I have a 2 dimensional array made up of letters in the first dimension and numbers in the second dimension. eg
a,1
b,3
c,9
d,8
What I would like to do is search to array for a character and return it's corresponding number. eg if $var='c' then the return value would be 9.
Being unfamiliar with Unix arrays, I was wondering if anyone knew how to do this simply?
Thanks :)
Here is what I came up with
arr1=(a b c d)
arr2=(1 3 9 8)
for ((index=0; index<${#arr1[#]}; index++)); do
if [ "${arr1[$index]}" = "$myCharacter" ]; then
echo $arr2[$index]
return
fi
done
echo 'Character not found'
Not sure if there was a shorter way to do this but works okay....
Assuming you have a file called array.txt with input like you show in the question,
$ var=c
$ awk -v key="$var" -F, '$1 ~ key {print $2; found=1} END { if (! found) { print "Key "key" not found";}}' array.txt
9
$ var=z
$ awk -v key="$var" -F, '$1 ~ key {print $2; found=1} END { if (! found) { print "Key "key" not found";}}' array.txt
Key z not found
You can use bash to prepare an associative array and lookup the value using the character:
declare -A ARR
ARR=( [a]=1 [b]=3 [c]=9 [d]=8 )
echo ${ARR[c]}

Resources