暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Shell脚本中碰到的坑-函数调用参数值传递丢失

原创 蔡璐 2025-08-26
74

最近在编写shell脚本的时候碰到个问题,解决后觉得很有意思,整理发出来让大家在以后编写shell脚本的时可以避免踩和我一样的坑。

最近在编写一个修改操作系统配置参数的脚本,需要修改的参数写入了脚本的变量`param_list` 中

# 更新系统参数,调整TCP连接参数
#!/bin/bash

# 设置日志文件路径
LOGFILE="/var/log/change_sysconf.log"

param_list="kernel.sem = 500 1024000 100 2048
kernel.shmmax = 404991166464"

# 清空日志和结果文件
> "$LOGFILE"

# 日志函数
log() {
local message="$1"
local level="${2:-INFO}"
local timestamp=$(date +"%Y-%m-%d %H:%M:%S")
echo "[$timestamp] [$level] $message" | tee -a "$LOGFILE"
}

change_sysconf(){
PARAM_NAME=$1
NEW_VALUE=$2
CONFIG_FILE="/etc/sysctl.conf"

# 检查配置项是否存在
if grep -q "^$PARAM_NAME" $CONFIG_FILE; then
# 使用sed修改已有配置项
sudo sed -i "s/^$PARAM_NAME =.*/$PARAM_NAME = $NEW_VALUE/" $CONFIG_FILE
echo "已更新 $PARAM_NAME 的值为 $NEW_VALUE" |tee -a "$LOGFILE"
else
# 如果配置项不存在,则追加到文件末尾
echo "$PARAM_NAME = $NEW_VALUE"| tee -a $CONFIG_FILE
echo "已添加 $PARAM_NAME = $NEW_VALUE$CONFIG_FILE" |tee -a "$LOGFILE"
fi
}

# 修改系统参数
echo "$param_list" | while read -r line;
do
# 使用等号分割每行,获取参数名和参数值
# 注意:这里使用 cut 命令,-d'=' 指定分隔符,-f1 获取第一部分(参数名),-f2- 获取第二部分及之后的所有内容(参数值)
param_name=$(echo "$line" | cut -d'=' -f1 | xargs) # xargs 用于去除首尾空格
param_value=$(echo "$line" | cut -d'=' -f2- | xargs)
change_sysconf $param_name $param_value
done



在执行脚本时查看日志发现修改的并不对:

kernel.sem = 500
已添加 kernel.sem = 500  /etc/sysctl.conf


    `kernel.sem = 500 1024000 100 2048` 参数在传递时,丢了一部分参数值;检查参数值是在什么时候丢的,使用-x 调试脚本发现参数在截取的时候并没有问题,但使用`change_sysconf $param_name $param_value`函数调用传递后参数值没有获取完全,函数在解析传入参数后`NEW_VALUE=500`。

+ read -r line
++ echo 'kernel.sem = 500 1024000 100 2048'
++ cut -d= -f1
++ xargs
+ param_name=kernel.sem
++ echo 'kernel.sem = 500 1024000 100 2048'
++ cut -d= -f2-
++ xargs
+ param_value='500 1024000 100 2048'
+ change_sysconf kernel.sem 500 1024000 100 2048
+ PARAM_NAME=kernel.sem
+ NEW_VALUE=500
+ CONFIG_FILE=/etc/sysctl.conf
+ grep -q '^kernel.sem' /etc/sysctl.conf
+ echo 'kernel.sem = 500'
kernel.sem = 500
+ echo '已添加 kernel.sem = 500 到 /etc/sysctl.conf'
+ tee -a /var/log/change_sysconf.log



传递的参数值为什么会丢失部分呢?


Shell 的默认行为是用空格来分割命令和参数。如果参数中没有引号,Shell 会将空格视为参数之间的分隔符,导致一个带空格的字符串被分解成多个参数。

导致了我们上面碰到的问题,只需要在参数传递的时候加上双引号("),让shell将参数作为一个整体进行传递就可以了。

只需要将`change_sysconf $param_name $param_value` 修改为 `change_sysconf "$param_name" "$param_value"`即可。


修改后调试日志:

+ read -r line
++ echo 'kernel.sem = 500 1024000 100 2048'
++ cut -d= -f1
++ xargs
+ param_name=kernel.sem
++ echo 'kernel.sem = 500 1024000 100 2048'
++ cut -d= -f2-
++ xargs
+ param_value='500 1024000 100 2048'
+ change_sysconf kernel.sem '500 1024000 100 2048'
+ PARAM_NAME=kernel.sem
+ NEW_VALUE='500 1024000 100 2048'
+ CONFIG_FILE=/etc/sysctl.conf
+ grep -q '^kernel.sem' /etc/sysctl.conf
+ echo 'kernel.sem = 500 1024000 100 2048'
kernel.sem = 500 1024000 100 2048
+ echo '已添加 kernel.sem = 500 1024000 100 2048 到 /etc/sysctl.conf'
+ tee -a /var/log/change_sysconf.log



最后修改时间:2025-08-26 10:54:46
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论