Case语句未捕获空字符串

时间:2018-07-29 09:49:25

标签: bash shell switch-statement

我想检测是否传递了任何参数或无效的参数,并输出帮助消息。可以单独检查空参数 ,但不太好。

我的bash脚本如下:

realloc

不传递任何参数时,将不执行任何操作;如果我通过“”,则将触发适当的情况。如果我直接使用COMMAND="$1" shift case "$COMMAND" in loop) loop_ ;; ... *) echo $"Usage: $0 {loop|...}" exit 1 esac 而不是使用临时变量,那么它将按预期工作。

我什至尝试为$1添加一个特定的案例,但无济于事。

4 个答案:

答案 0 :(得分:4)

您的case语句与没有给出的$1不匹配的唯一方法是,如果不是首先输入它的话。

请考虑以下内容:

#!/usr/bin/env bash
set -e

command=$1
shift
case $command in
  *) echo "Default case was entered";;
esac

在未设置$1时,此命令不会输出-但不会,因为case语句有任何问题。

相反,问题在于shift退出时的退出状态为非零值,当没有可用的移位键时,,并且set -e导致脚本整体退出那失败。


这个故事的第一道德:不要使用set -e(或#!/bin/bash -e

请参阅BashFAQ #105进行更详细的讨论-或急着使用exercises included thereinset -e is wildly incompatible在不同的“符合POSIX的”外壳之间,因此行为难以预测。手动错误处理可能不会很有趣,但是更加可靠。


第二:考虑使用功能

这为您提供了一种简洁的方法,可将您的使用情况信息放在一个地方,并在必要时重复使用(例如,如果您没有$1shift):< / p>

#!/usr/bin/env bash

usage() { echo "Usage: $0 {loop|...}" >&2; exit 1; }

command=$1
shift || usage
case $command in
  *) usage ;;
esac

由于|| usageshift的退出状态被视为“选中”,因此即使您使用set -e 运行脚本,它也会将不再构成致命错误。


或者,将shift标记为明确选中

类似地:

shift ||:

...将运行shift,但是如果:失败,则会退回到运行trueshift的同义词,在历史上/传统上,这意味着使用占位符) ,同样可以阻止set -e触发。


除了:使用小写名称作为自己的变量

POSIX specifies,仅通过具有全大写名称的环境变量来修改外壳(以及标准所适用的其他工具)的行为:

  

POSIX.1-2017的Shell and Utilities卷中的实用程序使用的环境变量名称仅由大写字母,数字和可移植字符集中定义的字符中的('_')组成,并且不以一个数字。实现可能允许使用其他字符;申请应容忍此类名称的存在。大写字母和小写字母应保留其唯一标识,并且不能折叠在一起。 包含小写字母的环境变量名称的名称空间保留给应用程序。应用程序可以使用此名称空间中的名称定义任何环境变量,而无需修改标准实用程序的行为。

这甚至适用于非export的常规shell变量,因为指定与环境变量同名的shell变量将覆盖后者。

例如,

BASH_COMMAND在bash中具有不同的含义-因此可以在脚本的开头将其设置为非空值。没有任何事情可以阻止COMMAND对兼容POSIX的Shell解释程序有意义并且已经被其使用。

如果要避免在shell设置了内置变量并使用脚本名称的情况下产生副作用,或者脚本意外覆盖了对shell有意义的变量,请使用小写或大小写混合的名称为兼容POSIX的外壳编写脚本时。

答案 1 :(得分:0)

您可以简单地使用$#。它代表给定参数的数量:

if [ $# = 0 ] 
then
  echo "help ..."
fi  

答案 2 :(得分:0)

在不更改常规模式的情况下解决问题的最简单方法是使用Bourne Shell中的“高级”参数扩展功能(这不是 bash 特定的)。在这种情况下,我们可以使用:-修饰符来提供默认值:

COMMAND="${1:-triggerusagemessage}"
shift
case "$COMMAND" in     
        loop)
            loop_
            ;;  
        ...            
        triggerusagemessage)
            echo $"Usage: $0 {loop|...}"
            exit 64
            ;;
esac

有关可用参数扩展修饰符的简短介绍,请参见外壳手册页中的“参数扩展”段落。

(请注意退出代码64,在某些操作系统上是为这种情况保留的。)

答案 3 :(得分:-2)

该行:echo $"Usage: $0 {loop|...}"的第一个$是做什么用的?

如果您不想重复此消息,只需将其放入函数中,并在case语句之前检查空字符串。

#! /bin/bash

die()
{
        "Usage: $0 {loop|...}"
        exit 1
}

COMMAND="$1"
[ -z $COMMAND ] && die 
shift
case "$COMMAND" in
        loop)
            loop_
            ;;
        *)
            die 
            exit 1
            ;;
esac