Reputation: 59
I'm writing a shell script and trying to use awk to pull a whole row from a .csv comma delimited file and stick it into an bash array. I can identify the row from it's first element (which is unique) & it needs to be an exact not partial match.
I'm expecting for the array to be filled by awk, but it seems to be putting it all into the first element
get_row() {
array=$(awk -F "," -v var="$1" '$1 == var { print }' csv_file )
echo ${array[@]}
}
I feel like i need to put a loop in somewhere to fill the array, but i'm not sure. Thanks in advance!
UPDATE
Im using a csv to store hostnames, ip addresses, shell port numbers usernames to write an ssh wrapper. I want to use this as a base function to reuse so i can pull out all the info i need (whenever i need it) for a specific machine i've got saved in my csv.
hostname,username,ip_address,ssh_port,sync_dir
the idea is that ill already know what is in each element of the scalar variable and use it appropriately something like (haven't got this far yet this isnt working code just an example of what im trying to achieve)
ssh "$array[2]" -p "$array[3]" -l "$array[1]"
Upvotes: 1
Views: 700
Reputation: 203607
Here's how to do what you asked for (in bash 4+ at least) given a bunch of caveats about how your CSV is populated (no embedded commas or newlines within fields for example, see What's the most robust way to efficiently parse CSV using awk?):
$ cat file
a,b,c
d,e,f
$ IFS=, read -r -a array < <(awk -F, -v var='d' '$1 == var' file)
or:
$ readarray -t array < <(awk -F, -v var='d' '$1 == var{gsub(FS,ORS); print}' file)
either of which populate array
as:
$ declare -p array
declare -a array=([0]="d" [1]="e" [2]="f")
I'd probably just use the read
approach instead of readarray
in this case since you're just reading one line and you have to make awk convert every comma to a newline for the readarray approach to work.
So your code would become, for example:
get_row() {
IFS=, read -r -a array < <(awk -F, -v var="$1" '$1 == var' file)
echo "${array[@]}"
}
get_row 'some_value'
ssh "${array[1]}" -p "${array[2]}" -l "${array[0]}"
or better since it doesn't require the array populated within the function to be global:
$ cat tst.sh
#!/bin/env bash
get_row() {
declare -n arrayName="$1"
local keyVal="$2"
IFS=, read -r -a arrayName < <(awk -F, -v var="$keyVal" '$1 == var' file)
}
get_row 'array' 'd'
echo ssh "${array[1]}" -p "${array[2]}" -l "${array[0]}"
$ ./tst.sh
ssh e -p f -l d
or you could have get_row()
just get the row and then populate array
with its output:
$ cat tst.sh
#!/bin/env bash
get_row() { awk -F, -v var="$1" '$1 == var' file; }
IFS=, read -r -a array < <(get_row 'd')
echo ssh "${array[1]}" -p "${array[2]}" -l "${array[0]}"
$ ./tst.sh
ssh e -p f -l d
Like with most things in UNIX you have lots of options :-).
Upvotes: 2
Reputation: 69
Hopefully below helps you
Lets consider csv_file have below data
# cat csv_file
a,b,c
d,e,f
g,h,i
Assigning output of awk to a variable named "array"
array=$(awk -F "," '{print $1}' csv_file)
where $1 represents column number of csv file
# echo $array
a d g
This output can be passed to a loop.
Upvotes: 0