Convert a line (containing strings and integers) into integer array in bash - arrays

I have a line which has space separated strings:
line="hello 3] 5c 100 memory"
I want to split this string into an integer array, so that the following:
echo ${arr[0]}
echo ${arr[1]}
echo ${arr[2]}
Outputs 3 5 100
Can someone help, please?

With Bash's Parameter expansion:
line="hello 3] 5c 100 memory"
arr=(${line//[^0-9 ]/}) # replace everything but 0-9 and space with nothing
declare -p arr
Output:
declare -a arr='([0]="3" [1]="5" [2]="100")'

Related

Passing and Parsing an Array from one shell script to another

Due to the limitation of 9 parameters in a script, my objective is to pass about 30 strings bundled in an array from calling script (scriptA) to called script (scriptB).
My scriptA looks something like this...
#!/bin/bash
declare -a arr=( ab "c d" 123 "string with spaces" 456 )
. ./scriptB.sh "Task Name" "${arr[#]}"
My scriptB looks something like this...
#!/bin/bash
arg1="$1"
shift
arg2=("$#")
read -a arr1 <<< "$#"
j=0
for i in "${arr1[#]}"; do
#echo ${arr1[j]}
((j++))
case "$j" in
"1")
param1="${i//(}"
echo "$j=$param1"
;;
"2")
param2="${i}"
echo "$j=$param2"
;;
"3")
param3="${i}"
echo "$j=$param3"
;;
"4")
param4="${i}"
echo "$j=$param4"
;;
"5")
param5="${i//)}"
echo "$j=$param5"
;;
esac
done
OUTPUT:
1=ab
2=c
3=d
4=123
5=string
Problem:
1. I see parenthesis ( and ) gets added to the string which I have to strip them out
2. I see an array element (with spaces) though quoted under double quotes get to interpreted as separate elements by spaces.
read -a arr1 <<< "$#"
is wrong. The "$#" here is equal to "$*", and then read will split the input on whitespaces (spaces, tabs and newlines) and also interpret \ slashes and assign the result to array arr1. Remember to use read -r.
Do:
arr1=("$#")
to assign to an array. Then you could print with:
for ((i=1;i<${#arr1};++i)); do
printf "%d=%s\n" "$i" "${arr1[$i]}"
done
of 9 parameters in a script, my objective is to pass about 30 strings bundled in an array from calling script (scriptA)
Ok. But "${arr[#]}" is passing multiple arguments anyway. If you want to pass array as string, pass it as a string (note that eval is evil):
arr=( ab "c d" 123 "string with spaces" 456 )
./scriptB.sh "Task Name" "$(declare -p arr)"
# Then inside scriptB.sh, re-evaulate parameter 2:
eval "$2" # assigns to arr
Note that the scriptB.sh is sourced in your example, so passing arguments.... makes no sense anyway.
I see an array element (with spaces) though quoted under double quotes get to interpreted as separate elements by spaces
Yes, because you interpreted the content with read, which splits the input on characters in IFS, which by default is set to space, tab and newline. You could print arguments on separate lines and change IFS accordingly:
IFS=$'\n' read -r -a arr1 < <(printf "%s\n" "$#")
or even use a zero terminated string:
mapfile -t -d '' arr1 < <(printf "%s\0" "$#")
but those are just fancy and useless ways of writing arr1=("$#").
Note that in your code snipped, arg2 is an array.

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

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[#]}"

bash string to array and array to string

How do we convert a string into N character array and back to string with spaces?
And how do we remove the spaces?
e.g. 123456789 into 2's should give 12 34 56 78 9
Sounds like you don't need the array at all and your final goal is just to insert spaces between groups of two characters. If that's the case you can use
sed 's/../& /g' <<< "your string here"
This will transform your example input 123456789 into the expected output 12 34 56 78 9.
Of course you can assign the result to a variable as usual:
yourVariable="$(sed 's/../& /g' <<< "your string here")"
if needed, how do we remove the spaces?
I'm not sure which spaces you mean. If you are talking about the final result, wouldn't it be easier to use the original input instead of procession the ouput again?
Anyways, you can remove all spaces from a any string using tr -d ' ' <<< "your string" or the parameter substitution ${yourVariable// /}.
$ str='123456789'
$ arr=( $(printf '%s\n' "$str" | sed 's/../& /g') )
$ declare -p arr
declare -a arr=([0]="12" [1]="34" [2]="56" [3]="78" [4]="9")
$ str="${arr[*]}"
$ echo "$str"
12 34 56 78 9
$ str="${str// }"
$ echo "$str"
123456789
$ str=$(printf "%s" "${arr[#]}")
$ echo "$str"
123456789
If you need to split a string into array, you can use IFS variable:
IFS=' '
arr=( )
read -r -a arr <<< "string morestring another"
unset IFS
To remove spaces from string you can use different approaches, one of them is:
str="123 123 12312312"
echo ${str// /}
//output: 12312312312312
This would be demonstrative to your question.
Convert a string into N character array:
string="0123456789abcdefghijklmnopqrstuvwxyz"
number_max_of_char_per_set=4
increment_by=$number_max_of_char_per_set
for i in `seq 0 $increment_by ${#string}`
#for i in $(seq 0 ${#string})
do array[$i]=${string:$i:number_max_of_char_per_set}
done
... back to string with spaces:
string_new=${array[#]}
echo "zero element of array is [${array[0]}]"
echo "entire array is [${array[#]}]"
echo $string_new
remove the spaces:
string_new=${string_new//[[:space:]]/}
echo $string_new

Bash - cut a text file into columns, slice strings and store value into arrays

I would like some advice on some code.
I want to write a small script that will take an input file of this format
$cat filename.txt
111222233334444555666661112222AAAA
2222333445556612323244455445454545
2334556345643534505435345353453453
(and so on)
It will be called as : script inputfile X (where X is the number of slices you want to do)
I want the script to read the file and column-ize the slices, depending on user input, ie if he gave input 1,2 for the first slice, 3,4 for the second, the output would look like this:
#Here the first slice starts on the second digit, and length = 2 digits
#Here the second slice starts on the 3th digit and legth=4 digits
111 1222
222 2333
233 3455
This is what i have so far, but i only get the outputs of the first slicing arranged in a line, any advice please?
$./columncut filename.txt 2
#Initialize arrays
for ((i=1 ; i <= $2; i++)); do
echo "Enter starting digit of $i string"; read a[i]
echo "Enter length in digits of $i string"; read b[i]
done
#Skim through file, slice strings
while read line
do
for i in "${!a[#]}"; do
str[i]=${line:${a[i]}:${b[i]}}
done
for i in "${!str[#]}"; do
echo -n "$i "
done
done <$1
I am unaware if there's an easier to do a job like this, perhaps with awk? Any help would be much appreciated.
#usage: bash slice.sh d.txt "1-2" "4-8" "10-20"
#column postions 1-2, 4-8 and 10-20 printed.
#Note that it is not length but col position.
inf=$1 # source file
shift # arg1 is used up for file discard it.
while read -r line
do
for fmt #iterate over the arguments
do
slice=`echo $line | cut -c $fmt` # generate one slice
echo -n "$slice " # oupt with two blanks, but no newline
done
echo "" # Now give the newline
done < "$inf"
Sample run:
bash slice.sh d.txt "1-2" "4-8" "10-15"
11 22223 334444
22 23334 555661
23 45563 564353
Probably it is not very difficult to store all these generated slices in array.

Reading a space-delimited string into an array in Bash

I have a variable which contains a space-delimited string:
line="1 1.50 string"
I want to split that string with space as a delimiter and store the result in an array, so that the following:
echo ${arr[0]}
echo ${arr[1]}
echo ${arr[2]}
outputs
1
1.50
string
Somewhere I found a solution which doesn't work:
arr=$(echo ${line})
If I run the echo statements above after this, I get:
1 1.50 string
[empty line]
[empty line]
I also tried
IFS=" "
arr=$(echo ${line})
with the same result. Can someone help, please?
In order to convert a string into an array, create an array from the string, letting the string get split naturally according to the IFS (Internal Field Separator) variable, which is the space char by default:
arr=($line)
or pass the string to the stdin of the read command using the herestring (<<<) operator:
read -a arr <<< "$line"
For the first example, it is crucial not to use quotes around $line since that is what allows the string to get split into multiple elements.
See also: https://github.com/koalaman/shellcheck/wiki/SC2206
In: arr=( $line ). The "split" comes associated with "glob".
Wildcards (*,? and []) will be expanded to matching filenames.
The correct solution is only slightly more complex:
IFS=' ' read -a arr <<< "$line"
No globbing problem; the split character is set in $IFS, variables quoted.
Try this:
arr=(`echo ${line}`);
If you need parameter expansion, then try:
eval "arr=($line)"
For example, take the following code.
line='a b "c d" "*" *'
eval "arr=($line)"
for s in "${arr[#]}"; do
echo "$s"
done
If the current directory contained the files a.txt, b.txt and c.txt, then executing the code would produce the following output.
a
b
c d
*
a.txt
b.txt
c.txt
line="1 1.50 string"
arr=$( $line | tr " " "\n")
for x in $arr
do
echo "> [$x]"
done

Resources