Reputation: 3
I have an issue where a number is printing twice when it should only be printing once before some output. I'll be highlighting the most relevant content, but to give context, I'll provide the entirety of my script.
#!/bin/bash
I load the out put of a ps aux
into an array.
N=0
for i in $(ps aux | awk '{print $11,$4}' | grep -v 0.0 | grep -v MEM | sort) ; do
array[$N]="$i"
let "N= $N + 1"
done
Here I split the array into two arrays
N=0
for i in `seq 0 ${#array[@]}`; do
if [ $(( $i % 2 )) -eq 0 ]; then arrayb[$N]=${array[$i]} ; else arrayc[$N]=${array[$i]} ;fi
let "N= $N + 1"
done
Now I look to combine duplicate entries (please pardon some of the convoluted variable naming; I was taking shots in the dark trying to trouble shoot).
N=0
c=0
for i in `seq 0 ${#arrayb[@]}`; do
let "B= $N - 1"
A=`echo ${arrayb[$B]} | tr -d '\n'`
B=`echo ${arrayb[$N]} | tr -d '\n'`
#A=${arrayb[$B]}
#B=${arrayb[$N]}
Here is where I check to see if the former array element is equal to the latter. If so combine and remove.
#if [ "$A" = "$B" ]; then
#arrayc[$N]=$(bc <<< ${arrayc[$N]}+${arrayc[$B]}); unset arrayb[$B];unset arrayc[$B]; echo trololo
#echo derp
#fi
The important part though is this. echo $c
then I echo $A $B
. My output however shows the following:
0
awk
1
awk
2
-bash
3
-bash
4
-bash
When it should be something like:
0
awk
awk
2
-bash
-bash
3
echo $c
echo -n "$A" "$B"
echo ""
let "c=$c+1"
let "N= $N + 1"
done
What I can't wrap my head around is how it prints a
then c
then b
then c
when it's all the same loop. Any assistance would be greatly appreciated.
Upvotes: 0
Views: 1358
Reputation: 753585
The first for
loop can be simplified to:
array=( $(ps aux | awk '$4 != 0.0 && $4 !~ /MEM/ {print $11,$4}' | sort) )
When written as a single fragment, the second loop is:
N=0
for i in `seq 0 ${#array[@]}`
do
if [ $(( $i % 2 )) -eq 0 ]
then arrayb[$N]=${array[$i]}
else arrayc[$N]=${array[$i]}
fi
((N++))
done
You are incrementing N every iteration, so you have arrayb[0]
containing a name and arrayc[1]
containing the corresponding memory usage. You should probably be using:
for i in `seq 0 ${#array[@]}`
do
if [ $(( $i % 2 )) -eq 0 ]
then arrayb[$((i/2))]=${array[$i]}
else arrayc[$((i/2))]=${array[$i]}
fi
done
However, you'd probably do better again to combine the first assignment with the second loop:
ps aux | awk '$4 != 0.0 && $4 !~ /MEM/ {print $11,$4}' | sort |
while read name memory
do
arrayb+=($name)
arrayc+=($memory)
done
The only snag here is that the arrays are set in a sub-shell which exits. Fortunately, bash
provides Process Substitution to evade that problem:
arrayb=()
arrayc=()
while read name memory
do
arrayb+=($name)
arrayc+=($memory)
done < <(ps aux | awk '$4 != 0.0 && $4 !~ /MEM/ {print $11,$4}' | sort)
Then your code currently is written as:
N=0
c=0
for i in `seq 0 ${#arrayb[@]}`; do
let "B= $N - 1"
A=`echo ${arrayb[$B]} | tr -d '\n'`
B=`echo ${arrayb[$N]} | tr -d '\n'`
echo $c
echo -n "$A" "$B"
echo ""
let "c=$c+1"
let "N= $N + 1"
done
And you've got a problem because you access arrayb
twice and ignore arrayc
. You also seem to be going through contortions to undo the unwanted incrementing in the original code for the second loop.
The use of back-ticks is generally a bad idea; use $(...)
instead. The tr -d '\n'
should be unnecessary. The use of echo -n "$A" "$B"
followed immediately by echo ""
is odd: echo "$A" "$B"
would suffice?
for i in $(seq 0 ${#arrayb[@]})
do
echo "${arrayb[$i]}" "${arrayc[$i]}"
done
So, we can reduce the script provided so far to:
arrayb=()
arrayc=()
while read name memory
do
arrayb+=($name)
arrayc+=($memory)
done < <(ps aux | awk '$4 != 0.0 && $4 !~ /MEM/ {print $11,$4}' | sort)
for i in $(seq 0 ${#arrayb[@]})
do
echo "${arrayb[$i]}" "${arrayc[$i]}"
done
From here, you can continue with the two arrays, arrayb
and arrayc
, organized so that matching indexes contain comparable values.
Upvotes: 1