shell Case语句未捕获空字符串

6ie5vjzr  于 2023-05-29  发布在  Shell
关注(0)|答案(5)|浏览(152)

我想检测是否没有参数或传递了无效参数,并打印帮助消息。单独检查空参数 * 是可能的,但不是那么优雅。
我的bash脚本看起来像这样:

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

当没有参数传递时,什么也不执行;如果我传递“”,则触发适当的case。如果我直接使用$1而不是使用临时变量,那么它就能按预期工作。
我甚至尝试为"")添加一个特定的case,但没有用。

yks3o0rb

yks3o0rb1#

#!/bin/bash
################################################################################
# Running this script with:                                                    #
#   * No option displays the specified message.                                #
#   * An invalid option displays the specified message.                       #
#   * A valid option displays the specified message.                           #
#   * An option with an argument displays the specified message.               #
#   * Multiple valid options display the specified messages for each.          #
#   * Arguments provided for options that don't require them will be ignored.  #
################################################################################
# Notes about getopts and how it handles arguments:                            #
#   * A colon before the options allows custom messages for missing arguments. #
#   * A colon after an option indicates that it requires an argument.          #
################################################################################
# In this example script:                                                      #
#   * Custom messages for missing arguments are allowed.                       #
#   * Options -a and -b and -c and -h are valid.                               #
#   * All other options are invalid.                                           #
#   * Option -a does not require an argument.                                  #
#   * Option -b requires an argument.                                          #
#   * Option -c requires an argument.                                          #
#   * Option -h does not require an argument.                                  #
################################################################################

case "$1" in
    # Valid options:
    -a | -b | -c | -h)
        # Loop through valid options, handling arguments:
        while getopts :ab:c:h opt;
            do
                case $opt in
                    # Valid option with missing argument:
                    :) echo "You must use an argument with the -$OPTARG option.";;
                    # Valid option:
                    a) echo "You have used the -$opt option.";;
                    # Valid option with argument:
                    b) echo "You have used the -$opt option with the $OPTARG argument.";;
                    # Valid option with argument:
                    c) echo "You have used the -$opt option with the $OPTARG argument.";;
                    # Valid option:
                    h) echo "You have used the -$opt option to display the help text.";;
                esac;
            done;
        ;;
    # Missing options:
    "") echo "You have not used an option.";;
    # Invalid options:
    *) echo "You have used the invalid $1 option.";;
esac
hs1ihplo

hs1ihplo2#

在线: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
nnvyjq4y

nnvyjq4y3#

case语句与没有给出的$1不匹配的唯一原因是它没有首先输入。
考虑以下几点:

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

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

$1未被设置时,它不会发出输出--但不会,因为case语句有任何错误。
相反,问题是shift在没有任何可用的shift* 时以非零的退出状态退出,并且set -e导致脚本在该失败时整体退出。

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

请参阅BashFAQ #105以获得详细讨论--或者如果赶时间的话,请参阅其中包含的练习。set -eis wildly incompatible,因此很难预测行为。手动错误处理可能并不有趣,但它可靠得多。

秒:考虑使用函数

这为您提供了一种简洁的方式,可以将使用信息放在一个地方,并在必要时重用它(例如,如果您没有$1shift):

#!/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,但如果shift失败,则会回退到运行:true的同义词,这在历史上/传统上意味着使用占位符),类似地防止set -e触发。

题外话:自己的变量使用小写名称

POSIX specifies shell(和其他适用标准的工具)的行为仅由具有全大写名称的环境变量修改:
POSIX. 1 -2017的Shell和Utilities卷中的实用程序所使用的环境变量名称仅由大写字母、数字和Portable Character Set中定义的字符中的('_')组成,并且不以数字开始。实现可能允许其他字符;应用程序应容忍此类名称的存在。大写字母和小写字母应保留其唯一标识,不得折叠在一起。环境变量名中包含小写字母的命名空间为应用程序预留。应用程序可以使用此命名空间中的名称定义任何环境变量,而无需修改标准实用程序的行为。
这甚至适用于常规的非export艾德shell变量,因为指定与环境变量同名的shell变量会覆盖后者。
例如,BASH_COMMAND在bash中有不同的含义,因此可以在脚本的前面设置为非空值。没有什么可以阻止COMMAND对POSIX兼容的shell解释器同样有意义,并且已经被POSIX兼容的shell解释器使用。
如果您想避免shell使用脚本使用的名称设置内置变量,或者脚本意外覆盖对shell有意义的变量的情况下的副作用,请在为POSIX兼容的shell编写脚本时坚持使用小写或大小写混合的名称。

balp4ylt

balp4ylt4#

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

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

有关可用的参数扩展修饰符的简短介绍,请参见shell手册页中的“参数扩展”段落。
(Note退出代码64,在某些操作系统上为这种情况保留)。

0s7z1bwu

0s7z1bwu5#

你可以使用$#。它表示给定参数的数量:

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

相关问题