views:

168

answers:

3

I've caught the functional programming bug, so naturally nothing is good enough for me anymore. ;)

So, in bash one could write:

case $status in
  "foo") status="bar" ;;
  "baz") status="buh" ;;
   *) status=$status ;;
esac

but I'm afraid of typos, so I'd prefer to write:

status=case $status in
  "foo") "bar" ;;
  "baz") "buh" ;;
  *) $status ;;
esac

The second form is invalid since the case evaluates to the exit code of the last executed command, which is not at all what I'm looking for.

Are there easy hacks to achieving what I am looking for?

+1  A: 

If you're sure status will only be one line, you could do something like this with sed:

status=$(echo "$status" | sed -e 's:^foo$:bar:' -e 's:^baz$:buh:')

You may also be able to get something to work with bash's built-in substitution. This almost works (I don't know of any way to get exact matching only):

status=${status/foo/bar}
status=${status/baz/buh}

If your goal is just to be more "functional" (and not to make your code more typo-proof), you could do this:

status=$(
  case "$status" in
    ("foo") echo "bar" ;;
    ("baz") echo "buh" ;;
    (*) echo "$status" ;;
  esac)

Though honestly, bash is probably one of the worst languages to try and be functional in. It was really designed with a more imperative mindset, as illustrated by the fact that you can't easily compose expressions. See in the second code snippet how I had to break it into two separate statements? If bash were designed to be functional you'd be able to write something like this instead:

status=${{status/baz/buh}/foo/bar}

But that does not work.

I'd suggest only using bash for simpler scripts, and for more complicated stuff use something like Python or Ruby. They'll let you write more functional code without having to constantly wrestle with the language.

Laurence Gonsalves
Way to not answer the question and add a lot of irrelevant information.
mbac32768
zsh will let you do nested parameter expansions like your last example.
Dennis Williamson
@mbac32768 as far as I can tell I did answer your question, three times in fact. If you disagree maybe you need to reword your question, or you could at least explain why these solutions don't work for you. Getting snarky when someone puts effort in trying to help you out is kind of lame.
Laurence Gonsalves
I read his answer to your question as "no, and here's why and some other options". Great answer.
John Meagher
No, you answered questions that were not asked and then you suggested not using bash, which is also useless.You would have been more helpful by not posting.
mbac32768
@mbac32768 Didn't you ask how to write that switch statement in a functional way? And didn't I show you three alternatives? As for pointing out that you shouldn't try to program functionally in bash, it's pretty it's very common for answers on Stack Overflow to take a step back and point out when the question indicates a bigger problem. If finding out that you're taking a walk down the garden path hurts your feelings then maybe you shouldn't be asking questions on Stack Overflow, or you can learn to deal with constructive criticism.
Laurence Gonsalves
A: 

Bash 4 has associative arrays:

# setup
unset vals i
indices=(foo baz)
val=(bar buh)
declare -A vals             # associative
for index in ${indices[@]}
do
    vals[$index]=${val[i++]}
done

$ # demos
$ status="foo"
$ status=${vals:-$status}
$ echo $status
bar
$ status="not found"
$ status=${vals:-$status}
$ echo $status
not found
Dennis Williamson
Is that really how you are supposed to initialise associative arrays in bash4?
Charles Stewart
@Charles: It's one way that's expedient for this demo. I could have done `for index in foo baz` for example, instead of using an array. Or done a direct bulk assignment or read from a file. What is it in particular that you're asking about?
Dennis Williamson
A: 
status="baz"
status=$(case $status in
  "foo") echo "bar" ;;
  "baz") echo "buh" ;;
  *) echo $status ;;
esac)
echo "status: $status"

output

$ ./shell.sh
status: buh
ghostdog74
That's the third snippet I posted, but with syntax errors. (The close parens inside `$(...)` confuse bash, so you need to use the optional open paren on each case.)
Laurence Gonsalves
what do you mean confuse bash?
ghostdog74
ok, i guess you are using bash <4.0 . In 4.0, i think this is fixed.
ghostdog74
Yeah, I'm still using 3.x (I'm using an LTS version of Ubuntu). It's interesting that 4 can parse that.
Laurence Gonsalves