Bash 脚本无法从 Firewalld 中删除服务列表

Bash 脚本无法从 Firewalld 中删除服务列表

我正在尝试清除firewalld通过 bash 脚本配置的所有现有服务。

# produces {cockpit,dhcpv6-client,ssh} as an example
local EXISTING_SERVICES="{$(firewall-cmd --permanent --list-service | sed -e 's/ /,/g')}"
# firewall-cmd --permanent --remove-service={cockpit,dhcpv6-client,ssh}
firewall-cmd --permanent --remove-service="${EXISTING_SERVICES}"

运行时,firewall-cmd返回:

Warning: NOT_ENABLED: {cockpit,dhcpv6-client,ssh}
success

问题似乎是将要firewall-cmd禁用的服务列表解释为单个服务名称,而不是列表。当我从 shell 手动运行命令时,完全相同的(复制/粘贴)命令按预期工作。

要复制的示例脚本:

EXISTING_SERVICES="{$(firewall-cmd --permanent --list-service | sed -e 's/ /,/g')}"
echo "firewall-cmd --permanent --remove-service=${EXISTING_SERVICES}"
firewall-cmd --permanent --remove-service="${EXISTING_SERVICES}"

结果:

壳牌结果

通过脚本运行和通过直接 shell 命令运行有什么区别?


更新:尝试按照@fra-san的建议运行脚本set -x,从脚本运行时产生以下结果:

结果

从 shell 运行时的结果如下:

在此输入图像描述

当交互运行时,shell(和/或firewalld)的行为似乎有所不同,并将服务列表扩展为3个单独的--remove-service=标志。这是非常出乎意料的行为。

答案1

firewall-cmd与此无关,区别不在于在脚本中运行命令和以交互方式运行命令之间。相反,您正在执行两个根本不同的命令。

您在行动中看到的是大括号扩展: 命令

firewall-cmd --permanent --remove-service={cockpit,dhcpv6-client,ssh}

被 Bash 扩展为

firewall-cmd --permanent --remove-service=cockpit --remove-service=dhcpv6-client --remove-service=ssh

这在脚本和命令行中都会发生。但请注意,shell 永远不会解析扩展结果以搜索进一步的扩展触发字符。因此,命令

firewall-cmd --permanent --remove-service="${EXISTING_SERVICES}"

在你的脚本中扩展为

firewall-cmd --permanent --remove-service={cockpit,dhcpv6-client,ssh}

并以该形式运行(大括号中的表达式在此时按字面意思理解)。

这似乎不是一个有效的firewall-cmd命令。引用man firewall-cmd,语法--remove-service

... --remove-service=service

删除一个服务。该选项可以指定多次。

建议在一次运行中删除多个服务的预期方式是

firewall-cmd ... --remove-service=foo --remove-service=bar ...

使用 Bash,您可以使用数组来存储启用的服务并构建相应的选项列表以删除它们:

services=( $(firewall-cmd --permanent --list-services) )
firewall-cmd --permanent "${services[@]/#/--remove-service=}"

${services[@]/#/--remove-service=}Bash 的参数扩展的模式替换形式在哪里—#匹配每个数组元素开头的空字符串并将其替换为--remove-service=.

虽然效率较低,但在某些情况下,一次添加/删除一项服务可能更实用,因为 的退出状态firewall-cmd设置为0if至少无论有多少操作失败,一项操作都会成功。那么您可能更喜欢以下内容:

services=( $(firewall-cmd --permanent --list-services) )
for serv in "${services[@]}"
do
  firewall-cmd --permanent --remove-service="$serv" || echo "failed: $serv" >&2
done

相关内容