首页 > 解决方案 > 仅在设置值时扩展为标志

问题描述

我有一些逻辑,例如:

if [[ -n "$SSH_CLIENT" ]]
then
    sflag="-s $(echo "$SSH_CLIENT" | awk '{ print $1}')"
else
    sflag=''
fi

iptables -A MY_RULE "$sflag" -p tcp -m tcp --dport 9999 -m conntrack -j ACCEPT

换句话说,我想模仿只将-s标志传递给iptablesifSSH_CLIENT设置。实际发生的是无意中传递了空字符串。

我感兴趣的是,为了不重复两个相当长的iptables调用,是否有可能扩展标志name 和 value。例如,上面的命令应该扩展为

问题是在第二种情况下,展开实际上变成了:

iptables -A MY_RULE '' -p tcp -m tcp

并且有一个额外的空字符串被视为位置参数。我怎样才能正确地做到这一点?

标签: bashshvariable-expansion

解决方案


所有 POSIX shell:使用${var+ ...expansion...}

仅当设置了变量时, Using${var+ ...words...}才允许您拥有任意数量的单词:

iptables -A MY_RULE \
  ${SSH_CLIENT+ -s "${SSH_CLIENT%% *}"} \
  -p tcp -m tcp --dport 9999 -m conntrack -j ACCEPT

在这里,如果设置了 if-and-only-if SSH_CLIENT,我们添加-s后面的所有内容,SSH_CLIENT直到第一个空格。


Bash(和其他扩展外壳):使用数组

更通用的方法是在要将多个字符串表示为单个值时使用数组:

ssh_client_args=( )
[[ $SSH_CLIENT ]] && ssh_client_args+=( -s "${SSH_CLIENT%% *}" )
iptables -A MY_RULE "${ssh_client_args[@]}" -p tcp -m tcp --dport 9999 -m conntrack -j ACCEPT

语法"${var%% *}是一个参数扩展,它扩展为var以空格开头的最长可能后缀;因此,留下第一个词。这比运行外部程序(如awk. 另请参阅描述本机 bash 字符串操作的一般最佳实践的BashFAQ #100 。


推荐阅读