我试图通过bash脚本清除在firewalld中配置的所有现有服务。
# 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命令运行这个程序有什么区别?
Update:按照@fra的建议,尝试使用set -x运行脚本,在从脚本运行时产生以下结果:

从shell运行以下结果:

在交互运行时,外壳(和/或firewalld)的行为似乎有所不同,并将服务列表扩展为3个单独的--remove-service=标志。这是非常出乎意料的行为。
发布于 2021-05-12 21:08:12
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的语法是
.-删除服务=服务删除服务可以多次指定此选项。
建议在一次运行中删除多个服务的预期方法是
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的退出状态设置为0。然后,您可能会更喜欢这样的东西:
services=( $(firewall-cmd --permanent --list-services) )
for serv in "${services[@]}"
do
firewall-cmd --permanent --remove-service="$serv" || echo "failed: $serv" >&2
donehttps://unix.stackexchange.com/questions/649428
复制相似问题