Sort lines in bash if they contain a word

Viewed 113

Sort & removal of duplicates Linux Bash

The desired sort is in ascending order:

  1. Removal of any duplicates
  2. Special sort

Special sort

  1. Print out 2 lines that does NOT contain the word "gmail"
  2. and THEN print only ONE line that contains the word "gmail".
  3. Repeat

If there are no more lines that does NOT contain the word "gmail", then it should just print the remaining sentences that contains the word "gmail" in alphabetical order.

Example list

test1@gmail.com 
test2@gmail.com 
test1@hotmail.com  
test3@gmail.com
test2@hotmail.com 
test3@hotmail.com 
test1@live.com 
test2@live.com

Desired results

test1@hotmail.com 
test2@hotmail.com 
test1@gmail.com 
test3@hotmail.com
test1@live.com 
test2@gmail.com 
test2@live.com 
test3@gmail.com

This can be done in coding by making 2 arrays and inserting every line containing the word "gmail" into one array, and inserting the rest into another array and then print them out in preferred order, but how would this be possible in Linux Bash if possible at all?

2 Answers

Using awk. It stores email addresses to two buffers, picks from the right one and deletes the printed ones to make it memory optimal.

$ awk '
function execute() {                     # stupid and undescriptive function name
    if(wc?email[et]:gmail[gt]) {         # test if printable exists
        print (wc?email[et]:gmail[gt])   # and print
        if(wc)
            delete email[et++]           # saving memory
        else
            delete gmail[gt++]
        return 1
    }
}
BEGIN {
    wc=gt=et=1                           # which counter, gmail and email top
}
!seen[$0]++ {                            # duplo dealer
    if(/@gmail\.com *$/) {               # domain matching regex
        gmail[++gb]=$0                   # gmail bottom counter
    } else {
        email[++eb]=$0                   # email bottom counter
    }
    if(execute())
        wc=++wc%3
}
END {
    do {
        execute()
        wc=++wc%3
    } while(!(et>eb&&gt>gb))
}' file

Output:

test1@hotmail.com  
test2@hotmail.com 
test1@gmail.com 
test3@hotmail.com 
test1@live.com 
test2@gmail.com 
test2@live.com
test3@gmail.com

With bash

list="test1@gmail.com
test2@gmail.com
test1@hotmail.com
test3@gmail.com
test2@hotmail.com
test3@hotmail.com
test1@live.com
test2@live.com"

# use the positional parameters as a queue
set --
count=0

while IFS= read -r email; do
    if [[ $email == *gmail* ]]; then
        set -- "$@" "$email"
    else
        echo "$email"
        if (( ++count == 2 )); then
            echo "$1"
            shift
            count=0
        fi
    fi
done <<<"$list" 
printf "%s\n" "$@"
test1@hotmail.com
test2@hotmail.com
test1@gmail.com
test3@hotmail.com
test1@live.com
test2@gmail.com
test2@live.com
test3@gmail.com
Related