3

I have a Bash script that looks like

#!/bin/bash
#
FECHA=`date +%j`

if [ $FECHA -eq 40 ]
then
    echo "Esta semana le toca preparar el café a Osvaldo" | mail -s 'Café' mailgroup@somedomain.mx
    exit
elif [ $FECHA -eq 47 ]
then
    echo "Esta semana le toca preparar el café a Berenice" | mail -s 'Café' mailgroup@somedomain.mx
    exit
elif [ $FECHA -eq 54 ]
then
    echo "Esta semana le toca preparar el café a Nizaá" | mail -s 'Café' mailgroup@somedomain.mx
    exit
fi

which will run, thanks to crontab, every monday at 7 am.

The actual Bash script has more lines, because there are more people involved. I think it works. But... Is there a way to make this script with fewer lines?

I was thinking: two variables, one for the person that will make the coffee and another for the date and a way to relate those variables.

| improve this question | | | | |
17

I think the case/esac construct fits well here.

#!/bin/bash

case "`date +%j`" in
  40) name=Osvaldo ;;
  47) name=Berenice ;;
  54) name=Nizaá ;;
  *) exit ;;
esac

echo "Esta semana le toca preparar el café a ${name}" \
   | mail -s 'Café' mailgroup@somedomain.mx

Note: if the same person needs to make coffee several times, you can aggregate tests with |:

case "`date +%j`" in
  12|23|40|49) name=Osvaldo ;;
  10|19|30|47) name=Berenice ;;
...
| improve this answer | | | | |
  • 1
    I used to code with a style guide requiring esac to be followed by the comment # is ridiculous. Just to make sure you don't forget. – Nick Matteo Feb 4 '15 at 19:17
6

This is a good case for an array. Here is an example:

mapping=([40]='Osvaldo'
         [47]='Berenice'
         [54]='Nizaá')

echo "Esta semana le toca preparar el café a ${mapping[FECHA]}" | mail -s 'Café' mailgroup@somedomain.mx

This eliminates the conditionals entirely.

| improve this answer | | | | |
  • 2
    This doesn't handle the case that $FECHA is not among those three - though the function in the question does. In fact this prints nonsense in that case, I think. This also gets a little dangerous if the value of $FECHA is not tested - a math substitution is nigh an eval. – mikeserv Feb 4 '15 at 7:51
  • According to http://google-styleguide.googlecode.com/svn/trunk/shell.xml: If you find you need to use arrays for anything more than assignment of ${PIPESTATUS}, you should use Python. No downvote, it is a nice solution for configuring the names on another place than the actual code. – Walter A Feb 4 '15 at 17:30
1

Put the names in a configfile, like coffee.txt:

040=Osvaldo
047=Berenice
054=Nizaá

When somebody is sick, fired or hired, you do not want to change your code:

name=$(grep "^$(date '+%j')=" coffee.txt | cut -d= -f2-)
echo "Esta semana le toca preparar el café a ${name}" \
   | mail -s 'Café' mailgroup@somedomain.mx
| improve this answer | | | | |
0
set -- 40 Osvaldo 47 Bernice 54 Nizaá
[ "${FECHA#[54][074]}" = "${FECHA%"${FECHA#44}"}" ] &&
until    [ "$((${1#$FECHA}0&&$#))" -eq 0 ]         &&
         printf "${1+%s\n}" "Esta semana le toca preparar el café a $2"
do       shift 2; done
[ "$#" -gt 1 ] && mail -s 'Café' mailgroup@somedomain.mx
| improve this answer | | | | |
  • If I didn't know better, I'd say that's almost Perl-like. Write-only. – muru Feb 4 '15 at 8:23
  • @muru - what's Write-only? – mikeserv Feb 4 '15 at 8:31
  • Something I'd be scared to modify: en.wikipedia.org/wiki/Write-only_language, stackoverflow.com/questions/2702728/… :D – muru Feb 4 '15 at 8:32
  • @muru - you could understand it if you tried. It just compares an acceptable case against an edge case each time it compares anything. Basically the problem is the names - it's easier to take in when it's all sequential arg numbers - stuff adds up in at case. Anyway, I find it easiest to allow values to test themselves - there's a lot less trouble to hunt down later on when you balance possibilities in the first place. Or, well, a lot less for me to hunt down. – mikeserv Feb 4 '15 at 8:37
  • 1
    @muru - anyway, the case answer is better. – mikeserv Feb 4 '15 at 8:50
0

If each code block after an if condition ends in exit, then you don't need an elif; simply end the conditional with fi.

I'm also a big fan of putting the then on the same line as the if which makes the code shorter in linecount and easier (quicker) to read IMHO. So your code becomes:

#!/bin/bash
#
FECHA=`date +%j`

if [ $FECHA -eq 40 ]; then
    echo "Esta semana le toca preparar el café a Osvaldo" | mail -s 'Café' mailgroup@somedomain.mx
    exit
fi
if [ $FECHA -eq 47 ]; then
    echo "Esta semana le toca preparar el café a Berenice" | mail -s 'Café' mailgroup@somedomain.mx
    exit
fi
if [ $FECHA -eq 54 ]; then
    echo "Esta semana le toca preparar el café a Nizaá" | mail -s 'Café' mailgroup@somedomain.mx
    exit
fi

Apart from that, in this case as the code is almost the same in each case here, I'd use Sam Hocevar's solution.

| improve this answer | | | | |
  • ? I don't understand the question... the if block is different in each case. And I already stated that Sam's answer would be more suited in this specific case. – wurtel Feb 4 '15 at 9:05
  • Sometimes it makes sense to write code that's easily understood, even if it may be slightly less efficient. I've come to this conclusion after 30+ years of programming experience. – wurtel Feb 4 '15 at 9:32
  • The question was about how to write code coe without all those elifs, not how to write the script in a totally different way. I think my answer adequately addresses the question. Again for the third time, I agree with Sam's answer which doesn't have any if so I don't get what you're trying to convince me of. Endof. – wurtel Feb 4 '15 at 9:41
  • The answer doesn't answer the question enough. It's a very specific answer because not all ifs end in exit. The point of the question was to reduce code significantly, rather than just a few characters here and there. – TankorSmash Feb 4 '15 at 16:55
  • The other answers already covered the "reduce code significantly" part (as I've said now for the 5th time), I just wanted to point out that you don't need an "else" part if the "if" part ends with exit, it's much easier to follow the thread of the program if unnecessary nesting is eliminated. Apparently a lot of people still don't get that point. I just hope those people don't write code I ever have to maintain or modify. – wurtel Feb 5 '15 at 7:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.