【Linux知识】Shell脚本中各类参数传递以及获取
Shell脚本中各类参数传递以及获取
- Linux Shell 参数传递与获取完全指南
- 一、基础参数传递方式
- 1. 位置参数(Positional Parameters)
- 2. 特殊参数变量
- 二、参数获取高级技巧
- 1. 参数遍历方法
- 2. 默认值设置
- 三、命令行选项解析
- 1. getopts(标准Unix方式)
- 2. getopt(增强版,支持长选项)
- 四、参数验证与安全
- 1. 必填参数检查
- 2. 类型校验
- 五、实用模式示例
- 1. 子命令模式(类似git)
- 2. 参数注入防护
- 六、性能优化技巧
- 1. 参数缓存处理
- 2. 批量参数处理
- 七、跨脚本参数传递
- 1. 导出到环境变量
- 2. 通过文件传递
- 最佳实践总结
Linux Shell 参数传递与获取完全指南
一、基础参数传递方式
1. 位置参数(Positional Parameters)
#!/bin/bash
调用方式:./script.sh param1 "param 2" param3echo "脚本名称: $0" # 脚本路径
echo "第一个参数: $1" # param1
echo "第二个参数: $2" # param 2 (保留空格)
echo "参数总数: $#" # 3
echo "所有参数: $*" # "param1 param 2 param3"(合并为单字符串)
echo "所有参数: $@" # "param1" "param 2" "param3"(保持独立)
2. 特殊参数变量
变量 | 描述 | 示例 |
---|---|---|
$# | 参数个数 | if [ $# -eq 0 ]; then... |
$* | 所有参数合并为单字符串 | for arg in "$*"; do... |
$@ | 所有参数独立保留 | for arg in "$@"; do... |
$? | 上条命令退出状态 | if [ $? -ne 0 ]; then... |
$$ | 当前进程PID | echo "PID: $$" |
$! | 最后一个后台进程PID | firefox & echo "Firefox PID: $!" |
二、参数获取高级技巧
1. 参数遍历方法
方法1:直接遍历$@
for param in "$@"; doecho "参数: $param"
done方法2:使用shift逐项处理
while [ "$1" != "" ]; docase $1 in-f|--file) shift; file=$1 ;;-v|--verbose) verbose=1 ;;*) echo "未知参数: $1"; exit 1 ;;esacshift # 移除已处理的参数
done
2. 默认值设置
如果未传参则使用默认值
username=${1:-"guest"}
port=${2:-8080}冒号语法(变量为空时也触发)
logfile=${LOG_FILE:?"必须设置LOG_FILE环境变量"}
三、命令行选项解析
1. getopts(标准Unix方式)
#!/bin/bash
while getopts ":a:b:c" opt; docase $opt ina) arg_a="$OPTARG" ;;b) arg_b="$OPTARG" ;;c) flag_c=1 ;;\?) echo "无效选项: -$OPTARG" >&2 ;;:) echo "选项 -$OPTARG 需要参数" >&2 ;;esac
done
shift $((OPTIND-1)) # 移除已解析选项调用示例:./script.sh -a value -b "test" -c file.txt
2. getopt(增强版,支持长选项)
#!/bin/bash
TEMP=$(getopt -o ab:c:: --long alpha,beta:,gamma:: -n '示例' -- "$@")
eval set -- "$TEMP"while true; docase "$1" in-a|--alpha) alpha=1; shift ;;-b|--beta) beta="$2"; shift 2 ;;-c|--gamma) case "$2" in"") gamma="default"; shift 2 ;;*) gamma="$2"; shift 2 ;;esac ;;--) shift; break ;;*) echo "内部错误"; exit 1 ;;esac
done调用示例:./script.sh --alpha --beta "value" --gamma=opt
四、参数验证与安全
1. 必填参数检查
required_params=("host" "port")
missing_params=()for param in "${required_params[@]}"; doif [ -z "${!param}" ]; then # 间接引用变量missing_params+=("$param")fi
doneif [ ${#missing_params[@]} -gt 0 ]; thenecho "缺少必要参数: ${missing_params[*]}"exit 1
fi
2. 类型校验
数字校验
if ! [[ "$port" =~ ^[0-9]+$ ]]; thenecho "端口必须是数字"exit 1
fi文件存在检查
if ! [ -f "$input_file" ]; thenecho "输入文件不存在: $input_file"exit 1
fiIP地址校验
if ! [[ "$ip" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; thenecho "无效IP地址"exit 1
fi
五、实用模式示例
1. 子命令模式(类似git)
case "$1" instart)shift # 移除子命令参数echo "启动服务,参数: $@" ;;stop)shiftecho "停止服务,参数: $@" ;;*)echo "用法: $0 {start|stop} [options]"exit 1 ;;
esac调用示例:./service.sh start --port 8080
2. 参数注入防护
危险!可能执行任意命令
eval "$1"安全做法:白名单验证
allowed_commands=("start" "stop" "restart")
if [[ " ${allowed_commands[*]} " =~ " $1 " ]]; thencase "$1" instart) ./start_service.sh ;;stop) ./stop_service.sh ;;esac
elseecho "无效命令"
fi
六、性能优化技巧
1. 参数缓存处理
缓存解析结果
parse_args() {local args=("$@")ARG_CACHE=""for arg in "${args[@]}"; doARG_CACHE+="$(printf '%q' "$arg") "done
}后续使用缓存
eval "set -- $ARG_CACHE"
2. 批量参数处理
使用关联数组存储参数
declare -A params
while IFS='=' read -r key value; doparams["$key"]="$value"
done < <(printf '%s\n' "$@")访问示例
echo "用户名: ${params["user"]}"
echo "端口: ${params["port"]}"
七、跨脚本参数传递
1. 导出到环境变量
主脚本
export DB_HOST="db.example.com"
export DB_PORT=3306
./subscript.shsubscript.sh
echo "连接数据库: ${DB_HOST}:${DB_PORT}"
2. 通过文件传递
生成参数文件
cat > params.conf <<EOF
input_file=/data/sample.txt
output_dir=/var/reports
max_records=1000
EOF读取参数文件
source params.conf
echo "处理文件: $input_file"
最佳实践总结
- 命名规范:使用有意义的参数名(如
--input-file
优于-i
) - 错误处理:对非法参数立即退出并显示帮助
- 安全防护:始终验证和清理输入参数
- 文档注释:在脚本头部添加参数说明
示例帮助文档:
usage() {cat <<EOF
用法: ${0##*/} [选项] 文件...选项:-h, --help 显示此帮助信息-v, --verbose 显示详细输出-o 文件 指定输出文件--version 显示版本信息示例:${0##*/} -o result.txt input*.log
EOFexit ${1:-0}
}