Tengo algo de lógica como:

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

En otras palabras, quiero imitar solo pasar el indicador -s a iptables si SSH_CLIENT está configurado. Lo que realmente sucede es que la cadena vacía se pasa inadvertidamente.

Estoy interesado en saber si es posible, en aras de no repetir dos llamadas iptables bastante largas, expandir la bandera nombre y valor . P.ej. el comando anterior debería expandirse a

  • iptables -A MY_RULE -s 10.10.10.10 -p tcp -m tcp ..., o
  • iptables -A MY_RULE -p tcp -m tcp ...

El problema es que en el segundo caso, la expansión en realidad se convierte en:

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

Y hay una cadena vacía adicional que se trata como un argumento posicional. ¿Cómo puedo lograr esto correctamente?

0
Brad Solomon 25 feb. 2020 a las 19:51

2 respuestas

La mejor respuesta

Todos los shells POSIX: utilizando ${var+ ...expansion...}

El uso de ${var+ ...words...} le permite tener un número arbitrario de palabras solo si se establece una variable:

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

Aquí, if-and-only-if SSH_CLIENT está configurado, agregamos -s seguido de todo en SSH_CLIENT hasta el primer espacio.


Bash (y otros shells extendidos): uso de matrices

El enfoque más general es utilizar una matriz siempre que desee representar varias cadenas como un solo valor:

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

La sintaxis "${var%% *} es una expansión de parámetros que se expande a {{X1} } con el sufijo más largo posible comenzando con un espacio recortado; dejando así la primera palabra. Esto es mucho más rápido que ejecutar un programa externo como awk. Consulte también BashFAQ # 100 que describe las mejores prácticas generales para la manipulación de cadenas de bash nativo.

4
Charles Duffy 25 feb. 2020 a las 17:08

Esta es una de esas ocasiones en las que probablemente no desee citar la expansión variable:

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

Alternativamente, y de manera más sólida, podemos usar la expansión ${var+...}:

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

Lea esto como "si $SSH_CLIENT está configurado (y no es nulo), luego expanda y sustituya -s "${SSH_CLIENT%% *}", de lo contrario nada".

Tenga en cuenta que no citamos la expansión $.+, pero sí citamos los argumentos individuales dentro de ella cuando sea necesario (obviamente -s no necesita comillas, aunque puede agregarlas si lo desea )

Eliminé el comando externo awk, ya que la expansión $.%% es la forma más simple y eficiente de truncar una cadena.

0
Toby Speight 25 feb. 2020 a las 17:05