简体   繁体   中英

Bash- parse file into arrays

i have this file

Seq1
10 1 5
10 2 6
10 3 9
Seq2
15 2 7
15 4 9
15 8 12

i want to have arrays for each Seqs (Seq1, Seq2) like this:

2ndColumn=(1,2,3) 
3rdColumn=(5,6,9)

i wrote this but it does not break the while loop..

#!/bin/bash
2ndColumn=()
3rdColumn=()
while read line 
do
if [[ $line == S* ]] 
 echo "$line"
else
 i=0
 while [[ $line != S* ]]
 do
  2ndColumn[i]="$(echo $line | cut -d\  -f2)"
  3rdColumn[i]="$(echo $line | cut -d\  -f3)"
  i=$((i+1))
  read line
 done
 echo "${2ndColumn[@]} and ${3rdColumn[@]}"
fi
done < file
exit 0

this script will iterate forever, it does not get out of while loop. please give a hand to this stupid humanbeing :(

I would restructure it to use a single loop instead of a nested loop with nested read calls on stdin:

2ndColumn=()
3rdColumn=()
i=0
while read line 
do
    if [[ $line == S* ]] 
        echo "$line ==> ${2ndColumn[@]} and ${3rdColumn[@]}"
        # reset the lists...
        2ndColumn=()
        3rdColumn=()
        i=0
    else
        2ndColumn[i]="$(echo $line | cut -d\  -f2)"
        3rdColumn[i]="$(echo $line | cut -d\  -f3)"
        i=$((i+1))
    fi
done

This will avoid issues with the inner read call, which is probably being blocked when fed a stdin file handle.

  • you can't change the cursor line of a while read

I wrote this for you with a little to prefix the array names with seq N+1 :

#!/bin/bash

file=file.txt

while read line; do
    if [[ $line == S* ]]; then
        echo "$line"
        i=0
        ((Seq++))
    else
        declare seq${Seq}_2ndColumn[i]="$(echo $line | cut -d\  -f2)"
        declare seq${Seq}_3rdColumn[i]="$(echo $line | cut -d\  -f3)"
        ((i++))
    fi
done < "$file"

echo "${!seq*} arrays are declared"

OUTPUT

seq1_2ndColumn seq1_3rdColumn seq2_2ndColumn seq2_3rdColumn arrays are declared

EXPLANATIONS

  • ${!pattern*} is a nice feature of bash to display variables beginning with pattern
  • (( )) is an arithmetic command, which returns an exit status of 0 if the expression is nonzero, or 1 if the expression is zero. Also used as a synonym for "let", if side effects (assignments) are needed. See http://mywiki.wooledge.org/ArithmeticExpression

BONUS

If you have the control on what's in your array, try doing this at the end ::

for s in ${!seq*}; do
    printf '\t%s\n' $(eval echo \${$s[@]})
done

See See http://mywiki.wooledge.org/BashFAQ/048

new OUTPUT

seq1_2ndColumn
        1
        2
        3
seq1_3rdColumn
        5
        6
        9
seq2_2ndColumn
        2
        4
        8
seq2_3rdColumn
        7
        9
        12
file=/PATH/TO/file.txt

arr1=( $(awk '/^Seq/{l++} l==1{print $2}' "$file") )
arr2=( $(awk '/^Seq/{l++} l==1{print $3}' "$file") )

echo "arr1:"
printf '\t%s\n' ${arr1[@]}

echo "arr2:"
printf '\t%s\n' ${arr2[@]}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM