Section 23.1: 多参数解析

要解析大量参数,首选方法是使用 while 循环、case 语句和 shift。

'shift' 命令用于偏移第一个参数,使过去是 $2 变为 $1。这对于一次性处理多个参数非常有用。

#!/bin/bash

# Load the user defined parameters
while [[ $# > 0 ]]
do
    case "$1" in

        -a|--valueA)
            valA="$2"
            shift
            ;;

        -b|--valueB)
            valB="$2"
            shift
            ;;

        --help|*)
            echo "Usage:"
            echo " --valueA \"value\""
            echo " --valueB \"value\""
            echo " --help"
            exit 1
            ;;
    esac
    shift
done

echo "A: $valA"
echo "B: $valB"

输入和输出的结果:

$ ./multipleParams.sh --help
Usage:
    --valueA "value"
    --valueB "value"
    --help

$ ./multipleParams.sh
A:
B:

$ ./multipleParams.sh --valueB 2
A:
B: 2

$ ./multipleParams.sh --valueB 2 --valueA "hello world"
A: hello world
B: 2

Section 23.2: 使用 for 循环进行参数解析

参数选项的例子

Opt Alt. Opt Details
-h --help 显示帮助
-v --version 显示版本信息
-dr path --doc-root path 采用辅助参数(根据一个路径)
-i --install 布尔选项 (true/false)
-* -- 无效选项
#!/bin/bash
dr=''
install=false

skip=false
for op in "$@";do
    if $skip;then skip=false;continue;fi
    case "$op" in
        -v|--version)
            echo "$ver_info"
            shift
            exit 0
            ;;
        -h|--help)
            echo "$help"
            shift
            exit 0
            ;;
        -dr|--doc-root)
            shift
            if [[ "$1" != "" ]]; then
                dr="${1/%\//}"
                shift
                skip=true
            else
                echo "E: Arg missing for -dr option"
                exit 1
            fi
            ;;
        -i|--install)
            install=true
            shift
            ;;
        -*)
            echo "E: Invalid option: $1"
            shift
            exit 1
            ;;
    esac
done

Section 23.3: 封装脚本

封装脚本是一个脚本里面封装了另一个脚本命令以提供额外的功能或只是为了减少冗长的操作。

例如,新 GNU/Linux 系统中的实际 grep -E 正在被一个名为 egrep 的封装脚本所取代。这是它的内容:

#!/bin/sh
exec grep -E "$@"

因此,当您在此类系统中运行 egrep 时,您实际上是在运行 grep -E 并转发所有参数。

在一般情况下,如果你想用另一个脚本 mexmp 运行一个示例脚本/命令 exmp,那么封装 mexmp 脚本将如下所示:

#!/bin/sh
exmp "$@" # Add other options before "$@"
# or
#full/path/to/exmp "$@"

Section 23.4: 访问参数

执行 Bash 脚本时,传入脚本的参数将根据其位置进行命名:“$1”是第一个参数的名称,“$2”是第二个参数的名称,依此类推。

缺少的参数的计算结果只是为空字符串。可以按如下方式检查参数是否存在:

if [ -z "$1" ]; then
    echo "No argument supplied"
fi

获取所有参数

'$@' 和 '$*' 是与所有脚本参数交互的方式。参考 Bash 手册页,我们看到:

  • '$*':扩展到位置参数,从 1 开始。当扩展发生在双引号内时,它将扩展为单个单词,每个参数的值由 IFS 特殊变量的第一个字符分隔。

  • '$@':扩展到位置参数,从 1 开始。当扩展发生在双引号内时,每个参数都会扩展为一个单独的单词。

获取参数数量

'$#' 获取传入脚本的参数数。一个典型的用例是检查是否传递了适当数量的参数:

if [ $# -eq 0 ]; then
    echo "No arguments supplied"
fi

示例 1

遍历所有参数并检查它们是否是文件:

for item in "$@"
do
    if [[ -f $item ]]; then
        echo "$item is a file"
    fi
done

示例 2

遍历所有参数并检查它们是否是文件:

for (( i = 1; i <= $#; ++ i ))
do
    item=${@:$i:1}

    if [[ -f $item ]]; then
        echo "$item is a file"
    fi
done

Section 23.5: 在 Bash 中将字符串拆分为数组

假设我们有一个 String 参数,我们想用逗号拆分它

my_param="foo,bar,bash"

要用逗号拆分这个字符串,我们可以使用;

IFS=',' read -r -a array <<< "$my_param"

在这里,IFS 是一个称为 Internal field separator 的特殊变量,它定义了用于将模式分隔为某些操作的标记的一个或多个字符。

要访问单个元素:

echo "${array[0]}"

要迭代元素:

for element in "${array[@]}"
do
    echo "$element"
done

要同时获取索引和值,请执行以下操作:

for index in "${!array[@]}"
do
    echo "$index ${array[index]}"
done