Расширение до флага, только если установлено значение - PullRequest
0 голосов
/ 25 февраля 2020

У меня есть логи c, например:

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

Другими словами, я хочу, чтобы mimi c только передавал флаг -s в iptables, если установлен SSH_CLIENT. Что на самом деле происходит, так это то, что пустая строка непреднамеренно передается.

Меня интересует, возможно ли, чтобы не повторять два довольно длинных вызова iptables, расширить флаг name и значение . Например, приведенная выше команда должна быть расширена до

  • iptables -A MY_RULE -s 10.10.10.10 -p tcp -m tcp ... или
  • iptables -A MY_RULE -p tcp -m tcp ...

Проблема заключается в том, что во втором случае расширение фактически становится:

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

и есть дополнительная пустая строка, которая обрабатывается как позиционный аргумент. Как я могу добиться этого правильно?

Ответы [ 2 ]

4 голосов
/ 25 февраля 2020

Все оболочки POSIX: Использование ${var+ ...expansion...}

Использование ${var+ ...words...} позволяет иметь произвольное количество слов, только если установлена ​​переменная:

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

Здесь, если установлено только-только-если 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. См. Также BashFAQ # 100 , описывающий общие рекомендации для нативных bash манипуляций со строками.

0 голосов
/ 25 февраля 2020

Это один из тех случаев, когда вы, вероятно, не хотите процитировать расширение переменной:

iptables -A MY_RULE $sflag -p tcp -m tcp ...

В качестве альтернативы и более надежно, мы можем использовать расширение ${var+...} :

 iptables -A MY_RULE ${SSH_CLIENT:+-s "${SSH_CLIENT%% *}"} -p tcp -m tcp ...

Прочитайте это как «если $SSH_CLIENT установлено (а не ноль), то разверните и подставьте -s "${SSH_CLIENT%% *}", иначе ничего».

Обратите внимание, что мы не цитируем расширение $.+, но мы цитируем отдельные аргументы в нем, где это необходимо (очевидно, -s не нужны кавычки, хотя вы можете добавлять их, если хотите).

Я удалил команда external awk, так как расширение $.%% является более простым и эффективным способом усечения строки.

...