#!/bin/sh __usage () { cat << EOH $0 -i file [-o file] $0 generates a Secret Santa list, making sure that no one in the same team gifts each other (e.g. spouses), and that no one gifts themselves. -i file: input file; default: none Input: full participant description, one per line # email team Full Name with spaces santa@cla.us XMas Santa Claus moviuro@popho.be noob Moviuro -o file: output file; default: out.${0##*/} this file will be overwritten if it exists Output: pair information, one per line # email_santa Full Santee Name santa@cla.us Moviuro moviuro@popho.be Santa Claus EOH } while getopts ":hi:o:" _opt ; do case " $_opt " in h ) __usage ; exit ;; i ) _in = " $OPTARG " ;; o ) _out = " $OPTARG " ;; * ) __usage > & 2 ; exit 1 ;; esac done [ -z " $_out " ] && _out = "out. ${ 0 ##*/ } " : " ${ _in ?requires an input file } " : > " $_out " _lines = $( wc -l < " $_in " ) printf '%s

' "This might take a while." > & 2 # Shuffle the input, read that line-by-line at the same time as the original; # check coherence at each step while [ " $( wc -l < " $_out " ) " ! = " $_lines " ] ; do _cur_pair = 0 : > " $_out " sort -R < " $_in " | while read -r _santa_mail _santa_team _ ; do # Fail fast: if the output file's line count is not equal to our current # pair number, it means that one of the previous pairing attempts failed: # we exit the loop. [ " $( wc -l < " $_out " ) " ! = " $_cur_pair " ] && break _cur_pair = $(( _cur_pair + 1 )) sed -n " ${ _cur_pair } p" < " $_in " | { read -r _santee_mail _santee_team _santee_name if [ " $_santa_team " ! = " $_santee_team " ] ; then # Current santa must gift someone not on their team ! echo " $_santa_mail $_santee_name " >> " $_out " fi } done done