Sorting the contents of a variable

i want to reduce the OPTIONS variable which is a list of email addresses to just the unique entries. The following works, but, i would like to accomplish it without using the temporary file (dest.txt)

$echo $OPTIONS                         
a b c A B D                                         
$cat clean                             
#!/usr/bin/bash                                     
n=$#                                                
i=1                                                 
cat /dev/null >/usr/spool/lp/temp/dest.txt          
while [ $i -le $n ]                                 
do                                                  
        c=$(echo $1 |tr "[:upper:]" "[:lower:]" )   
        echo $c>>/usr/spool/lp/temp/dest.txt        
        shift                                       
        let i=$i+1                                  
done                                                
sort -u </usr/spool/lp/temp/dest.txt                
                                                    
$ OPTIONS1=$(./clean $OPTIONS)          
$ echo $OPTIONS1                        
a b c d                                             
$                                       

echo "4 2 d c b 1 a b A b 1 B C a b c d" | ./clean.awk

# output
 a b c d 1 2 4
 

clean.awk

#!/usr/bin/awk -f
{
   for(i=1;i<=NF;i++)
      a[tolower($i)]=1
} 

END{ 
   for(i in a)
      printf i " "
   printf "\n"
}
 

awk seems to have a sorting algorithm when accessing lists.

...or in one line:

echo "4 2 d c b 1 a b A b 1 B C a b c d" | awk '{for(i=1;i<=NF;i++) {a[tolower($i)]=1}} END{for(i in a) {printf i " "} ; printf "\n"}'

How about:

OPTIONS="a b c A B D"

OPTIONS=$( \
               echo "${OPTIONS}" | \
               tr " " "\n" | \
               tr "[:upper:]" "[:lower:]" | \
               sort -u | \
               tr "\n" " " \
         )

I've just broken up the lines for clarity. Does that do the job?

Not a great plan if the content of $OPTIONS is very large (a few million items) and would be terrible with any values containing a space.

Also, don't call this in a loop because of the many many processes it might create and the costs associated with that.

Robin

After a little thought:

#!/usr/bin/bash                                   
n=$#                                              
i=1                                               
C=""                                              
while [ $i -le $n ]                               
do                                                
        c=$(echo $1 |tr "[:upper:]" "[:lower:]" ) 
        C="$c\n$C"                                
        shift                                     
        let i=$i+1                                
done                                              
echo $C |sort -u             

How about

$ echo $(shuf -e ${OPTIONS,,} | sort -u)
 a b c d

(provided your system's bash provides "Parameter Expansion / Case modification" and shuf has the -e option)

EDIT: or

$ echo $( xargs -n1 -d" " <<< ${OPTIONS,,} | sort -u)
 a b c d

or, of course,

$ echo $( tr ' ' '\n' <<< ${OPTIONS,,} | sort -u)
1 Like

Assuming that $OPTIONS does not expand to a string containing anything other than alphanumeric characters and <space>s, one could also use:

echo $(echo $OPTIONS|tr ' [:upper:]' '\n[:lower:]'|sort -u)

without worrying about having a shell that supports the case modification parameter expansion or the shuf utility which are both extensions to the standards.

1 Like