找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

3519

积分

0

好友

467

主题
发表于 2 小时前 | 查看: 3| 回复: 0

在运维工作中,编写 Shell 脚本处理命令行参数几乎是家常便饭。但很多朋友一遇到复杂的参数组合——比如长短选项、辅助参数、布尔开关——就有些头疼。其实,掌握几种经典模式后就能轻松应对。如果你想系统提升脚本处理能力,云栈社区上有大量实战经验分享。

下文将围绕 Bash 参数处理,由浅入深地拆解 while + case + shift 组合拳、for 循环解析、包装脚本设计,以及如何把字符串快速切分成数组。

23.1 多参数解析

当你需要解析大量参数时,最推荐的方法是利用 while 循环搭配 case 语句和 shift

shift 的作用是“弹出”参数列表的第一个元素,原本的 $2 会变成 $1$3$2,以此类推。这让我们可以逐个消耗参数,非常适合顺序解析。

#!/bin/bash
# 加载用户定义的参数
while [[ "$#" -gt 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

23.2 使用 for 循环解析参数

还有一种更直观的思路——用 for 循环逐项检查 $@。以下脚本提供了几个典型选项:

选项 替代形式 描述
-h --help 显示帮助
-v --version 显示版本信息
-dr --doc-root 带有一个辅助参数(路径)的选项
-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

这里的 skip 标记用于跳过已作为辅助参数消耗掉的元素,避免遍历混乱。你是否也曾因为遗漏类似逻辑而抓狂?

23.3 包装脚本

包装脚本(Wrapper Script)本质上是对另一个脚本或命令的封装,用来提供额外功能或简化常用操作。

例如,在一些较新的 GNU/Linux 系统中,真实的 egrep 早已被一个包装脚本取代。它的内容可以精简到这种程度:

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

所以,当你在这些系统上敲下 egrep 时,实际运行的是 grep -E,并且所有参数原封不动地转发过去。

推而广之,如果你想用一个叫 mexp 的脚本来包装 expm 命令,只需这样写:

#!/bin/sh
expm "$@"           # 在 "$@" 之前可以添加其他选项
# 或者
# full/path/to/expm "$@"

是不是比想象中简单得多?

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

23.5 在 Bash 中将字符串分割成数组

假如我们拿到一个字符串参数,希望按逗号拆分成数组:

my_param="foo,bar,bash"

用它来构造数组可以借助 IFSread 一步到位:

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

这里 IFS(Internal Field Separator,内部字段分隔符)定义了哪些字符用来切分标记。操作完成后,可以这样访问单个元素:

echo "${array[0]}"   # 输出:foo

遍历所有元素:

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

如果需要同时获取索引和值:

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

至此,这些 Bash 参数处理技巧已经覆盖了绝大多数场景。多练几次,你自然就能根据实际需求灵活选择最合适的方案。




上一篇:Worklog:本地优先项目管理桌面端,适合小团队和独立开发者
下一篇:Browser-Use:让AI长出手和眼,自动替你搞定那些重复网页操作
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-5-26 05:41 , Processed in 0.634922 second(s), 42 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表