0

I saved a single line sql result to a file.

AA 10 BB 20 DD 14 GG 14

I want to count the numbers next to each words and save it as variables.
And if there's none(like CC) it should be counted as 0.

aCnt=10
bCnt=20
cCnt=0

Can 'grep' or 'awk' do this?

3
  • How do you know that CC should be zero? What about ZL, NA, PQ, or any other word that does not exist in your output?
    – Kusalananda
    Apr 13 at 19:28
  • @Kusalananda wow. At first I didn't think of that as a problem because I was only dealing with pre-determined names. But now that I have to deal with undefined names, it's causing troubles. I need some awk soccery.
    – Lunartist
    Apr 16 at 10:16
  • (1) What do you mean by “count”? (2) Can a “word” appear more than once, as in AA 5 AA 12 BB 2000 BB 21? (3) Will the numbers always be positive integers? Or can there be FF 1.5 NN -42 PP 3.14159 ZZ 0? (4) Will the “words” always be in alphabetic order? (5) Please respond to Kusalananda’s comment — will the “words” always be AA, BB, CCZZ, or can there be A, ZL, FOO or F17? … … … … … … … … … … … … … … … … … … Please do not respond in comments; edit your question to make it clearer and more complete. Apr 21 at 1:50
1

I think you'd be better off with an associative array instead of a bunch of individual variables:

line="AA 10 BB 20 DD 14 GG 14"
read -ra words <<< "$line"

declare -A cnt
for ((i = 0; i < ${#words[@]}; i += 2)); do
    label=${words[i]} 
    num=${words[i+1]}
    cnt[${label:0:1}]=$num
done

declare -p cnt      # => declare -A cnt=([G]="14" [D]="14" [B]="20" [A]="10" )

Now:

letter=A
echo "$letter count is ${cnt[$letter]:-0}"  # => A count is 10
letter=C
echo "$letter count is ${cnt[$letter]:-0}"  # => C count is 0

With individual variables, we can use declare for "dynamic" variable names:

for a in {a..z}; do
    declare "${a}Cnt=0"
done
line="AA 10 BB 20 DD 14 GG 14"
declare -l letter     # lowercase
while [[ $line =~ ([A-Z]+)" "([0-9]+)(.*) ]]; do
    letter=${BASH_REMATCH[1]:0:1}
    declare "${letter}Cnt=${BASH_REMATCH[2]}"
    line=${BASH_REMATCH[3]}
done

Now we have:

$ set | grep '.Cnt'
aCnt=10
bCnt=20
cCnt=0
dCnt=14
eCnt=0
fCnt=0
gCnt=14
hCnt=0
iCnt=0
jCnt=0
kCnt=0
lCnt=0
mCnt=0
nCnt=0
oCnt=0
pCnt=0
qCnt=0
rCnt=0
sCnt=0
tCnt=0
uCnt=0
vCnt=0
wCnt=0
xCnt=0
yCnt=0
zCnt=0
1

Equally crazy awk.....since that's the tag

awk -vRS=" " '{a=tolower(substr($0,1,1)); getline; aa[a]=$0}
     END{for (a=97; a<=122; a++) {A=sprintf("%c",a); print A"Cnt="aa[A]+0}}' file

Break records RS on , an associative array and a bit of jiggery pokery with the string characters

aCnt=10
bCnt=20
cCnt=0
dCnt=14
eCnt=0
fCnt=0
gCnt=14
hCnt=0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.