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 ...
, oiptables -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?
2 respuestas
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.
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.
Nuevas preguntas
bash
Para preguntas sobre scripts escritos para el shell de comandos Bash. Para los scripts de shell con errores / errores de sintaxis, verifíquelos con el programa shellcheck (o en el servidor web shellcheck en https://shellcheck.net) antes de publicar aquí. Es más probable que las preguntas sobre el uso interactivo de Bash sean sobre el tema en Superusuario que en Stack Overflow.