[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 832
  • Last Modified:

How to sort Unix shell variable - Array

I have the array variables like below:

arr_name[1]='ADAM'      arr_id[1]=9999
arr_name[2]='XEROX'    arr_id[2]=1234
arr_name[3]='PENNY'    arr_id[3]=8767

I want sort the array variable by

1) arr_id[]  
2) arr_name[]

if sort by arr_name, th resulting array variable will be:

arr_name[1]='ADAM'      arr_id[1]=9999
arr_name[2]='PENNY'     arr_id[2]=8767
arr_name[3]='XEROX'     arr_id[3]=1234

if sort by arr_id, the result should be

arr_name[1]='XEROX'   arr_id[1]=1234
arr_name[2]='PENNY'    arr_id[2]=8767
arr_name[3]='ADAM'     arr_id[3]='9999

Please also provide the solution of Descending order

Notice:  I want a simple command to do the sorting NOT a solution contain a loop of compare this and that
0
tindavid
Asked:
tindavid
  • 9
  • 8
  • 3
  • +1
1 Solution
 
wesly_chenCommented:
> I want a simple command to do the sorting NOT a solution contain a loop of compare this and that
The short answer is NO.  You have two arrays, not just one array. So there is no way to sort two arrays with associated items without loop.
Here is the URL
http://ubuntuforums.org/archive/index.php/t-1689348.html

#!/bin/bash

arr_name=( ADARM XEROX PENNY )
arr_id=( 9999   1124   8767 )

echo BEFORE:
echo ${arr_name[@]}
echo ${arr_id[@]}

tmp=$( for (( i=0; i<${#arr_name[@]}; i++ ))
do
echo ${arr_name[i]} ${arr_id[i]}
done | sort -nk2)  # ascend by arr_name  : sort
                   # descend by arr_name : sort -r
                   # ascend by arr_id    : sort -nk2
                   # descend by arr_id   : sort -nrk2

arr_name=( $( echo "$tmp" | awk '{print $1 }' ) )
arr_id=( $( echo "$tmp" | awk '{print $2 }' ) )

echo AFTER:
echo ${arr_name[@]}
echo ${arr_id[@]}

Open in new window

0
 
oleggoldCommented:
SORT -U SHOULD DO THE THING
0
 
oleggoldCommented:
usage
sort -u $1 | \
while read arr_name
do
# ..................... whatever
done
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
oleggoldCommented:
they also use sort-u here:
http://programming.itags.org/unix-linux-programming/96608/
You can also use perl or awk but this ultimately will be NOT "simple command to do the sorting "
0
 
TintinCommented:
echo "${arr_name[@]}"| tr ' ' '\n' | sort | tr '\n' ' '

Open in new window


echo "${arr_id[@]}"| tr ' ' '\n' | sort -rn | tr '\n' ' '

Open in new window

0
 
tindavidAuthor Commented:
Hi Wesly,

After adding your code to my test program, got an error:


$ sh test.sh 5
Before sorting ...
 54 myname01
 53 myname02
 52 myname03
 51 myname04
 50 myname05

test.sh[39]: Syntax error at line 1 : `((' is not expected.



Please help

test.sh
0
 
tindavidAuthor Commented:
Hi All,

I want to sort array of variables NOT just single array.

arr_id[]  arr_name[]  arr_address[]  etc
0
 
TintinCommented:
If your data structure is like that, then I'd suggest that you either need to look at another type of data structure or programming language.

Can you go back a few steps and describe what you are trying to achieve with your data?
0
 
wesly_chenCommented:
array index start from 0, not 1, please change your test.sh to "i=0" and  "j=0"

#!/bin/ksh

build_array()
{
  temp_val=`expr ${arridx} + 50`
  i=0
  while [ $i -le $arridx ]
  do
     arr_id[$i]=`expr ${temp_val} - $i`
     arr_name[$i]="myname0${i}"
     i=`expr $i + 1`
  done
  idx=${#arr_id[*]}
}

print_array()
{
  j=0
  while [ $j -le ${1} ]
  do
    echo " ${arr_id[$j]} ${arr_name[$j]}"
    j=`expr $j + 1`
  done
}

if [ $# -ne 1 ] && [ ${1} -ge 2 ]; then
   echo "Usage $0 number_of_array"
   exit
fi

arridx=${1}
build_array
echo "Before sorting ..."
print_array $arridx

tmp=$( for (( i=0; i<${#arr_name[@]}; i++ ))
do
echo ${arr_name[i]} ${arr_id[i]}
done | sort -nk2)  # ascend by arr_name  : sort
                   # descend by arr_name : sort -r
                   # ascend by arr_id    : sort -nk2
                   # descend by arr_id   : sort -nrk2

arr_name=( $( echo "$tmp" | awk '{print $1 }' ) )
arr_id=( $( echo "$tmp" | awk '{print $2 }' ) )

echo "After sort"
print_array $arridx

Open in new window

0
 
wesly_chenCommented:
As my comment in the code, for ascending or descending, just change the line 39
done | sort -nk2)  # ascend by arr_id
to
done | sort )     # ascend by arr_name
or
done | sort -r ) # descend by arr_name
or
done | sort -nrk2)   # descend by arr_id
0
 
wesly_chenCommented:
@Tintin
What tindavid want is more like hash in perl or bash4.

@tindavid
Perl hash is more easier.
Here is the sample.

#!/usr/bin/perl -w

# DEFINE A HASH
%hash = ( "ADARM" => 9999,
          "XEROX" => 1234 ,
          "PENNY" => 8767 );
# Sort by keys
print "Sort by keys:\n";
foreach $key (sort keys %hash) {
     print "$key $hash{$key}\n";
}
# Sort by values
print "Sort by values:\n";
foreach $value (sort {$hash{$a} cmp $hash{$b} } keys %hash) {
     print "$value $hash{$value}\n";
}

Open in new window

0
 
tindavidAuthor Commented:
I prefer a shell solution.

Wesly, still error is executing line of

tmp=$(........ )
do
   .....
done

I am doing this in HP-UX are you ?
0
 
wesly_chenCommented:
Sorry, change the first line from
#!/bin/ksh
to
#!/bin/bash

Make sure you have bash shell on HP-UX
0
 
tindavidAuthor Commented:
noop, does not work as you suggested.  

Can you write a korn shell for this ?
0
 
wesly_chenCommented:
I don't have HP-UX. Tested with the ksh on Linux and it works for me.
#!/bin/ksh

build_array()
{
  temp_val=`expr ${arridx} + 50`
  i=0
  while [ $i -le $arridx ]
  do
     arr_id[$i]=`expr ${temp_val} - $i`
     arr_name[$i]="myname0${i}"
     i=`expr $i + 1`
  done
  idx=${#arr_id[*]}
}

print_array()
{
  j=0
  while [ $j -le ${1} ]
  do
    echo " ${arr_id[$j]} ${arr_name[$j]}"
    j=`expr $j + 1`
  done
}

if [ $# -ne 1 ] && [ ${1} -ge 2 ]; then
   echo "Usage $0 number_of_array"
   exit
fi

arridx=${1}
build_array
echo "Before sorting ..."
print_array $arridx

cat /dev/null > /tmp/2d_array
c=0
while [ $c -lt ${#arr_name[@]} ]
do
    echo "${arr_id[c]} ${arr_name[c]}" >> /tmp/2d_array
    c=`expr $c + 1`
done

arr_id=(`[b]sort[/b] /tmp/2d_array | awk '{print $1 }' | sed ':a;N;$!ba;s/\n/ /g'`)
arr_name=(`[b]sort[/b] /tmp/2d_array | awk '{print $2 }' | sed ':a;N;$!ba;s/\n/ /g'`)

rm -f /tmp/2d_array

echo "After sort"
print_array $arridx

Open in new window

0
 
wesly_chenCommented:
line 44 and 45 should be
arr_id=(`sort /tmp/2d_array | awk '{print $1 }' | sed ':a;N;$!ba;s/\n/ /g'`)
arr_name=(`sort /tmp/2d_array | awk '{print $2 }' | sed ':a;N;$!ba;s/\n/ /g'`)
0
 
TintinCommented:
In 99% of cases with shell scripts, arrays aren't needed as there is generally a much easier and more efficient way of handling the processing.

Please explain how you want to manipulate your data.
0
 
tindavidAuthor Commented:
echo "After sort"
print_array $arridx
hp800l[montr92][/home/dba/oracle/dtin] >ksh test4.sh 5
Before sorting ...
 55 myname00
 54 myname01
 53 myname02
 52 myname03
 51 myname04
 50 myname05
test4.sh[38]: syntax error at line 44 : `(' unexpected

still error
0
 
wesly_chenCommented:
It seems like ksh on HP-UX doesn't support array=( item1  item2 ).
Modified the whole script as
-----------
#!/bin/ksh

build_array()
{
  temp_val=`expr ${arridx} + 50`
  i=0
  while [ $i -le $arridx ]
  do
     arr_id[$i]=`expr ${temp_val} - $i`
     arr_name[$i]="myname0${i}"
     echo "${arr_id[$i]} ${arr_name[$i]}" >> /tmp/2d_array
     i=`expr $i + 1`
  done
  idx=${#arr_id[*]}
}

sort_array()
{
  c=0
  sort /tmp/2d_array | while read id name    # Change sort to "sort -r", "sort -k2", or "sort -kr2"
  do
     arr_id[$c]=$id
     arr_name[$c]=$name
     c=`expr $c + 1`
  done
}


print_array()
{
  j=0
  while [ $j -le ${1} ]
  do
    echo "${arr_id[$j]} ${arr_name[$j]}"
    j=`expr $j + 1`
  done
}

if [ $# -ne 1 ] && [ ${1} -ge 2 ]; then
   echo "Usage $0 number_of_array"
   exit
fi

cat /dev/null > /tmp/2d_array
arridx=${1}
build_array
echo "Before sorting ..."
print_array $arridx
sort_array

rm -f /tmp/2d_array

echo "After sort"
print_array $arridx

#!/bin/ksh

build_array()
{
  temp_val=`expr ${arridx} + 50`
  i=0
  while [ $i -le $arridx ]
  do
     arr_id[$i]=`expr ${temp_val} - $i`
     arr_name[$i]="myname0${i}"
     echo "${arr_id[$i]} ${arr_name[$i]}" >> /tmp/2d_array
     i=`expr $i + 1`
  done
  idx=${#arr_id[*]}
}

sort_array()
{
  c=0
  sort /tmp/2d_array | while read id name
  do
     arr_id[$c]=$id
     arr_name[$c]=$name
     c=`expr $c + 1`
  done
}

print_array()
{
  j=0
  while [ $j -le ${1} ]
  do
    echo "${arr_id[$j]} ${arr_name[$j]}"
    j=`expr $j + 1`
  done
}

if [ $# -ne 1 ] && [ ${1} -ge 2 ]; then
   echo "Usage $0 number_of_array"
   exit
fi

cat /dev/null > /tmp/2d_array
arridx=${1}
build_array
echo "Before sorting ..."
print_array $arridx
sort_array

rm -f /tmp/2d_array

echo "After sort"
print_array $arridx

Open in new window

0
 
wesly_chenCommented:
You can remove line 11 and add
---------
join_arrays_to_file()
{
  c=0
  while [ $c -lt ${#arr_name[@]} ]
  do
    echo "${arr_id[c]} ${arr_name[c]}" >> /tmp/2d_array
    c=`expr $c + 1`
  done
}
#!/bin/ksh

build_array()
{
  temp_val=`expr ${arridx} + 50`
  i=0
  while [ $i -le $arridx ]
  do
     arr_id[$i]=`expr ${temp_val} - $i`
     arr_name[$i]="myname0${i}"
     i=`expr $i + 1`
  done
  idx=${#arr_id[*]}
}

join_arrays_to_file()
{
  c=0
  while [ $c -lt ${#arr_name[@]} ]
  do
    echo "${arr_id[c]} ${arr_name[c]}" >> /tmp/2d_array
    c=`expr $c + 1`
  done
}

sort_array()
{
  c=0
  sort /tmp/2d_array | while read id name # Change sort to "sort -r", "sort -k2", or "sort -kr2"
  do
     arr_id[$c]=$id
     arr_name[$c]=$name
     c=`expr $c + 1`
  done
}

print_array()
{
  j=0
  while [ $j -le ${1} ]
  do
    echo "${arr_id[$j]} ${arr_name[$j]}"
    j=`expr $j + 1`
  done
}

if [ $# -ne 1 ] && [ ${1} -ge 2 ]; then
   echo "Usage $0 number_of_array"
   exit
fi

cat /dev/null > /tmp/2d_array
arridx=${1}
build_array
echo "Before sorting ..."
print_array $arridx
join_arrays_to_file
sort_array

rm -f /tmp/2d_array

echo "After sorting ..."
print_array $arridx

Open in new window

0
 
tindavidAuthor Commented:
Dear All,

Seems like there is not simple command to perform sorting of array variables in Korn Shell. If I have to use temp file, I have already had my complex solution to do that , instead I have a solution that will not use temp file but still able to sort the array variable using comparsion method.


sortarray.sh
0
 
tindavidAuthor Commented:
if there is no simple soltion to sort array variables, then I have to call for deletion of this question.  Thank you for your help.
0
 
tindavidAuthor Commented:
No other simple code for this sorting of array variables
0

Featured Post

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

  • 9
  • 8
  • 3
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now