在Bash中解析命令行参数的两种样例脚本

问题

假设,我有一个脚本,它会被这样一行调用:

./myscript -vfd ./foo/bar/someFile -o /fizz/someOtherFile

或者这个:

./myscript -v -f -d -o /fizz/someOtherFile ./foo/bar/someFile

如何解析 $v$f$d,使它们都被设置为 true,并且 $outFile 等于 /fizz/someOtherFile ?


回答

以空格分隔选项和参数

样例程序如下:

cat >/tmp/demo-space-separated.sh <<'EOF'
#!/bin/bash

POSITIONAL_ARGS=() #初始化一个空数组,用来存储位置参数

while [[ $# -gt 0 ]]; do  #当命令行参数的数量大于0时,进入循环
  case $1 in
    -e|--extension)  #如果参数是这个,脚本会将紧随其后的参数(文件扩展名)保存在变量 EXTENSION 中
      EXTENSION="$2"
      shift # 跳过参数
      shift # 跳过后面的值
      ;;
    -s|--searchpath)  #如果参数是这个,脚本会将紧随其后的参数(搜索路径)保存在变量 SEARCHPATH 中
      SEARCHPATH="$2"
      shift # 跳过参数
      shift # 跳过后面的值
      ;;
    --default)  #如果参数是这个,脚本会将变量 DEFAULT 设置为 YES
      DEFAULT=YES
      shift # 跳过参数
      ;;
    -*|--*)  #如果参数是以 - 或 -- 开头且未知的选项,打印错误信息并退出
      echo "Unknown option $1"
      exit 1
      ;;
    *)  #对于所有其他非选项参数(即位置参数),将它们逐一添加到 POSITIONAL_ARGS 数组中,
      POSITIONAL_ARGS+=("$1") # 保存位置参数
      shift
      ;;
  esac
done

set -- "${POSITIONAL_ARGS[@]}" # 将数组里的参数设置为当前 shell 的位置参数

echo "FILE EXTENSION  = ${EXTENSION}"
echo "SEARCH PATH     = ${SEARCHPATH}"
echo "DEFAULT         = ${DEFAULT}"
echo "Number files in SEARCH PATH with EXTENSION:" $(ls -1 "${SEARCHPATH}"/*."${EXTENSION}" | wc -l)

if [[ -n $1 ]]; then
    echo "The non option arguments are:" $@
fi
EOF

chmod +x /tmp/demo-space-separated.sh

/tmp/demo-space-separated.sh -e log -s /var/log pos1 pos2

复制粘贴上述代码块的输出:

在这里插入图片描述

推荐用法:

demo-space-separated.sh -e log -s /var/log pos1

以等号分隔选项和参数

样例程序如下:

cat >/tmp/demo-equals-separated.sh <<'EOF'
#!/bin/bash

for i in "$@"; do  #循环遍历所有的命令行参数
  case $i in
    -e=*|--extension=*)
      EXTENSION="${i#*=}"  #使用 ${i#*=} 来提取等号 = 后面的值(即文件扩展名),并将其保存在变量 EXTENSION 中
      shift # past argument=value
      ;;
    -s=*|--searchpath=*)
      SEARCHPATH="${i#*=}"
      shift # past argument=value
      ;;
    --default)
      DEFAULT=YES
      shift # past argument with no value
      ;;
    -*|--*)
      echo "Unknown option $i"
      exit 1
      ;;
    *)
      ;;
  esac
done  #结束for循环

echo "FILE EXTENSION  = ${EXTENSION}"
echo "SEARCH PATH     = ${SEARCHPATH}"
echo "DEFAULT         = ${DEFAULT}"
echo "Number files in SEARCH PATH with EXTENSION:" $(ls -1 "${SEARCHPATH}"/*."${EXTENSION}" | wc -l)

if [[ -n $1 ]]; then
    echo "The non option arguments are:" $@
fi
EOF

chmod +x /tmp/demo-equals-separated.sh

/tmp/demo-equals-separated.sh -e=log -s=/var/log pos3 pos4

其中 ${i#*=} 用于删除参数 $i 从左边开始匹配的第一个 = 及其左边的所有字符。

复制粘贴上述代码块的输出:

在这里插入图片描述

推荐用法:

demo-equals-separated.sh -e=log -s=/var/log pos1 pos2

参考

  • stackoverflow question 192249
  • https://www.gnu.org/software/bash/manual/bash.html#The-Set-Builtin
  • https://www.gnu.org/software/bash/manual/bash.html#Shell-Parameter-Expansion

相关阅读:

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-06-07 15:00:03       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-06-07 15:00:03       100 阅读
  3. 在Django里面运行非项目文件

    2024-06-07 15:00:03       82 阅读
  4. Python语言-面向对象

    2024-06-07 15:00:03       91 阅读

热门阅读

  1. React 和 Vue的跨端|跨平台框架介绍

    2024-06-07 15:00:03       26 阅读
  2. Mysql中表的常用约束

    2024-06-07 15:00:03       28 阅读
  3. 邮件地址搜索软件

    2024-06-07 15:00:03       25 阅读
  4. Linux下进程的创建(嵌入式)

    2024-06-07 15:00:03       24 阅读
  5. Uniapp与第三方应用数据通讯

    2024-06-07 15:00:03       24 阅读
  6. Python基础教程 第2版 PDF下载

    2024-06-07 15:00:03       30 阅读
  7. 【缓存】框架层常见问题和对策

    2024-06-07 15:00:03       28 阅读