Case语句会计算字符串。

23

我已经被函数式编程所迷惑,所以自然地,对于我来说,没有什么东西再合适不过了。 ;)

因此,在bash中可以这样写:

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

但我害怕打错字,所以我更倾向于写成:

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

第二种形式是无效的,因为该情况评估为最后执行命令的退出代码,这完全不是我想要的。

有没有简单的技巧来实现我所期望的?


你只是想要编写一个函数吗? - thecoshman
1
如果你担心打错字,可以在程序开头使用 set -u - ceving
3个回答

25

如果你确定状态只有一行,你可以使用sed进行如下操作:

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

你也可以尝试使用bash内置的替换功能。这个方法几乎有效(我不知道有什么方法可以只进行精确匹配):

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

如果你的目标只是为了更加“functional”(而不是使你的代码更加容错),你可以这样做:

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

老实说,bash可能是最不适合尝试以函数式方式编程的语言之一。它的设计更倾向于命令式思维方式,这可以从无法轻松组合表达式的事实得到证明。请看第二段代码片段,我如何将其分成了两个单独的语句?如果bash被设计为函数式的,你应该能够像这样写:

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

但那样不起作用

我建议只在编写简单脚本时使用bash,在处理更复杂的任务时使用Python或Ruby等语言。它们会让你编写更加功能强大的代码,而不必经常与语言进行搏斗。


zsh可以让你像上一个例子那样进行嵌套参数扩展。 - Dennis Williamson
14
就我所知,实际上我已经回答了你的问题,事实上是三次。如果你不同意,也许你需要重新措辞你的问题,或者你至少可以解释一下为什么这些解决方案对你不起作用。当有人尽力帮助你时,却变得咄咄逼人是有点差劲的。 - Laurence Gonsalves
1
我理解他对你的问题的回答是“不行,这是原因,还有其他选择”。非常好的回答。 - John Meagher
5
@mbac32768,你不是问如何以函数式的方式编写那个开关语句吗?我不是向你展示了三种替代方案吗?至于指出你不应该在Bash中尝试函数式编程,对于Stack Overflow上的答案来说,当问题表明存在更大问题时,退一步指出是非常常见的。如果发现你正在走弯路让你感到不悦,也许你就不应该在Stack Overflow上提问,或者你可以学会处理建设性的批评。 - Laurence Gonsalves
@mbac32768,“status=$(...echo...)”这个东西怎么就不能回答你的问题呢?你一直在寻找一个解决方法,现在你有了。坦白地说,你在这里表现得很不友善(或者8年前是这样的)。 - scravy

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

输出

$ ./shell.sh
status: buh

1
这是我发布的第三个代码片段,但存在语法错误。($(...) 中的右括号会让 bash 混淆,因此您需要在每个 case 中使用可选的左括号。) - Laurence Gonsalves
你的意思是困惑于Bash吗? - ghostdog74
好的,我猜你正在使用bash <4.0。在4.0中,我认为这个问题已经解决了。 - ghostdog74
1
是的,我仍在使用3.x(我正在使用Ubuntu的LTS版本)。有趣的是4可以解析它。 - Laurence Gonsalves

-1

Bash 4有关联数组:

# 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

这真的是在bash4中初始化关联数组的正确方式吗? - Charles Stewart
1
@Charles:这是一个方便进行演示的方法之一。例如,我可以使用for index in foo baz来代替使用数组。或者直接进行批量赋值或从文件中读取。你特别想了解什么? - Dennis Williamson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接