Store grep output containing whitespaces in an array - arrays

I want to store some lines of the output of blkid in an array. The problem is, that those lines contain whitespace and the array syntax takes those as delimiters for single array elements, so that i end up with splitted lines in my array instead of one line beeing one array element.
This is the code i currently have:
devices=($(sudo blkid | egrep '^/dev/sd[b-z]'))
echo ${devices[*]} gives me the following output:
/dev/sdb1: LABEL="ARCH_201108" TYPE="udf"
/dev/sdc1: LABEL="WD" UUID="414ECD7B314A557F" TYPE="ntfs"
But echo ${#devices[*]} gives me 7 but insted i want to have 2. I want /dev/sdb1: LABEL="ARCH_201108" TYPE="udf" to be the first element in my devices array and /dev/sdc1: LABEL="WD" UUID="414ECD7B314A557F" TYPE="ntfs" to be the second one. How can i accomplish that?

Array elements are split on the IFS value. If you want to split on newline, adjust IFS:
IFS_backup=$IFS
IFS=$'\n'
devices=($(sudo blkid | egrep '^/dev/sd[b-z]'))
IFS=$IFS_backup
echo ${#devices[#]}

Related

How to get user input as number and echo the stored array value of that number in bash scripting

I have wrote a script that throws the output of running node processes with the cwd of that process and I store the value in an array using for loop and do echo that array.
How can I able to get the user enter the index of array regarding the output that the script throws and show the output against that input generated by user
Example Myscript
array=$(netstat -nlp | grep node)
for i in ${array[*]}
do
echo $i
done
output is something like that
1056
2064
3024
I want something more advance. I want to take input from user like
Enter the regarding index from above list = 1
And lets suppose user enter 1
Then next output should be
Your selected value is 2064
Is it possible in bash
First, you're not actually using an array, you are storing a plain string in the variable "array". The string contains words separated by whitespace, so when you supply the variable in the for statement, the unquoted value is subject to Word Splitting
You need to use the array syntax for setting the array:
array=( $(netstat -nlp | grep node) )
However, the unquoted command substitution still exposes you to Filename Expansion. The best way to store the lines of a command into an array is to use the mapfile command with a process substitution:
mapfile -t array < <(netstat -nlp | grep node)
And in the for loop, make sure you quote all the variables and use index #
for i in "${array[#]}"; do
echo "$i"
done
Notes:
arrays created with mapfile will start at index 0, so be careful of off-by-one errors
I don't know how variables are implemented in bash, but there is this oddity:
if you refer to the array without an index, you'll get the first element:
array=( "hello" "world" )
echo "$array" # ==> hello
If you refer to a plain variable with array syntax and index zero, you'll get the value:
var=1234
echo "${var[0]}" # ==> 1234

Count unique values in a bash array

I have an array ${sorted[#]}. How can I count the frequency of occurrence of the elements of the array.
e.g:
Array values:
bob
jane
bob
peter
Results:
bob 2
jane 1
peter 1
The command
(IFS=$'\n'; sort <<< "${array[*]}") | uniq -c
Explanation
Counting occurrences of unique lines is done with the idiom sort file | uniq -c.
Instead of using a file, we can also feed strings from the command line to sort using the here string operator <<<.
Lastly, we have to convert the array entries to lines inside a single string. With ${array[*]} the array is expanded to one single string where the array elements are separated by $IFS.
With IFS=$'\n' we set the $IFS variable to the newline character for this command exclusively. The $'...' is called ANSI-C Quoting and allows us to express the newline character as \n.
The subshell (...) is there to keep the change of $IFS local. After the command $IFS will have the same value as before.
Example
array=(fire air fire earth water air air)
(IFS=$'\n'; sort <<< "${array[*]}") | uniq -c
prints
3 air
1 earth
2 fire
1 water

Using 'awk' to store specific line numbers in an array

I have a destination.properties file:
Port:22
10.52.16.156
10.52.16.157
10.52.16.158
10.52.16.159
10.52.16.160
10.52.16.161
10.52.16.162
10.52.16.163
10.52.16.164
10.52.16.165
10.52.16.166
10.52.16.167
10.52.16.168
10.52.16.169
Port:61900-61999
10.52.16.156
10.52.16.157
10.52.16.158
10.52.16.159
10.52.16.160
10.52.16.161
10.52.16.162
10.52.16.163
10.52.16.164
10.52.16.165
10.52.16.166
10.52.16.167
10.52.16.168
10.52.16.169
I want to use an awk command to store all of the line numbers of lines that contain the word 'Port:' in an array.
I have the following command which stores all of the line numbers in the 1st array value ie array[0]:
array=$( (awk '/Port:/ {print NR}' destinations.prop) )
To get them in a shell array, you can do:
array=( $(awk '/Port:/ {print NR}' destinations.prop) )
The parenthesis assign the words within to successive array members. As usual, IFS controls the splitting of that command output, and file name globbing also happens if you happen to output wildcard characters. Probably not an issue in this case.

Sort multiple column String array in bash

I have an array of strings:
arr[0]="1 10 2Z6UVU6h"
arr[1]="1 12 7YzF5mFs"
arr[2]="2 36 qRwAiLg7"
How could i sort by the 2nd column and use the 1st as a tie break.
Is there anything similar to something like...
sort -k 2,2n -k 1,1 $arr
As long as there are no newline characters in any array element, it's straight-forward: Just printf the array into sort and capture the output:
mapfile -t sorted < <(printf "%s\n" "${arr[#]}" | sort -k2,2n -k1,1)
(The use of process substitution is to avoid having the mapfile run in a subshell, which wouldn't be helpful since the goal is to set the value of $sorted in this shell.)
If the array elements might contain newlines, then you could use NUL as a delimiter in the printf and the sort (option -z for sort), but you'd have to replace mapfile with an explicit loop because mapfile does not offer an option to change the line delimiter. read does (-d '' will cause read to use NUL as a line delimiter), but it only reads one line at a time.

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

Resources