Bash Capturing Output of Awk into Array

Bash capturing output of awk into array

Add additional parentheses, like this:

myarr=($(ps -u kdride | awk '{ print $1 }'))

# Now access elements of an array (change "1" to whatever you want)
echo ${myarr[1]}

# Or loop through every element in the array
for i in "${myarr[@]}"
do
:
echo $i
done

See also bash — Arrays.

Put result of awk into an array

When you say:

result=($(awk /string/ $files | awk -F, '{OFS=",";print $1,$4,$17}'))

the output would be split by whitespace. Set IFS to a newline character, and you should see the desired result. Say:

IFS=$'\n' result=($(awk /string/ $files | awk -F, '{OFS=",";print $1,$4,$17}'))

instead to capture different lines of output into an array.

Store each occurence found by awk to an array

As Charles suggested...

Edited to strip the newline off the and of the block (not every record)

while IFS= read -r -d '' x; do array+=("$x"); done < <(awk '
/PATTERN1/,/PATTERN2/ { if ( $0 ~ "PATTERN2" ) { x=$0; printf "%s%c",x,0; next }
print }' ./file.txt)

I reformatted it. It was getting kinda busy and hard to read.

And to test it -

$: echo "[${array[1]}]"
[PATTERN1
Some line of text 9
Some line of text 10
Some line of text 11
PATTERN2]

As an aside, it seems very odd to me to include the redundant sentinel values in the data elements, so if you want to strip those:

$: while IFS= read -r -d '' x; do array+=("$x"); done < <(
awk '/PATTERN1/,/PATTERN2/{ if ( $0 ~ "PATTERN1" ) { next }
if ( $0 ~ "PATTERN2" ) { len--;
for (l in ary) { printf "%s%c", ary[l], l<len ? "\n" : 0; }
delete ary; len=0; next }
ary[len++]=$0;
}' ./file.txt )

$: echo "[${array[1]}]"
[Some line of text 9
Some line of text 10
Some line of text 11]

Building array from awk output


I think its because of how I am trying to set the array.

Each command in a pipeline | is run in a subshell - as a separate process. The parent process does not "see" variable changes from a child process.

Just:

array=($(grep letter "$1" | awk '{print $4}'))

or

array=($(awk '/letter/{print $4}' "$1"))

Run variable assignment in the parent shell.

Bash (v.2.03) capture awk output to array not working


BashFAQ/024 - I set variables in a loop that's in a pipeline. Why do they disappear after the loop terminates? Or, why can't I pipe data to read?

Bash pipe-lines create a sub-shell in which the variables updated are not reflected at all. In your case either of your array array and counter variable scopes are lost soon after the sub-shell terminates. Use process-substitution(<( … )) in bash as below

Also the array subscript you are using is incorrect; which should have been done as

array[$counter]="$line"

Combining the two,

while read -r line; do
echo "$line"
echo "$counter"
array[$counter]="$line"
counter=$((counter+1))
done < <(/usr/xpg4/bin/awk -F '[[:blank:]]{2,}' 'FNR > 4 { for (i=1; i<=NF; i++) if ($i != "") print $i;}' my-file)

awk: passing output to associative array

One possibility:

typeset -a lines=("${(f)$(awk 'BEGIN {FS="|"} {print $1,$2,$3}' test.csv)}")
typeset -a keys=("${(@)lines% *}")
typeset -a vals=("${(@)lines##* }")
typeset -A ary=(${keys:^vals})

Some of the pieces:

  • ${(f)...} - splits the output from awk at line breaks.
  • ${...% *} - removes everything from the last space to the end, leaving the first two fields for the key. With the (@) and double-quotes, this is applied to each element in the lines array.
  • ${...##* } - removes everything up to the last space, leaving the value.
  • ${...:^...} - zips two arrays together, so we end up with key1 val1 key2 val2 ....
  • typeset -A ... - creates an associative array using the k1 v1 k2 v2 ... syntax.

Another version, using only zsh:

typeset -a lines=("${(f)$(<test.csv)}")
typeset -a keys=("${(@)"${(@)lines%|*}"//|/ }")
typeset -a vals=("${(@)lines##*|}")
typeset -A ary=(${keys:^vals})

This variant and the one below can handle spaces in the value, e.g. j k|rowling|44 192 411 in the .csv file will create the element ['j k rowling']='44 192 411'.


With some changes to the awk script, it can be done in a single line:

typeset -A ary=("${(@s:|:)${(f)"$(awk -F'|' '{print $1,$2"|"$3}' test.csv)"}}")


Related Topics



Leave a reply



Submit