Iterar sobre la salida de un comando en bash sin una subshell

9

Quiero recorrer la salida de un comando sin crear un sub-shell o usar un archivo temporal.

La versión inicial de mi script se veía así, pero esto no funciona ya que crea una subshell, y el exitcomando termina la subshell en lugar del script principal que se requiere. Es parte de un script mucho más grande para configurar el enrutamiento de políticas, y detiene la ejecución si detecta una condición que hará que el enrutamiento falle.

sysctl -a 2>/dev/null | grep '\.rp_filter' | while read -r -a RPSTAT ; do

  if [[ "0" != "${RPSTAT[2]}" ]] ; then
    echo >&2 "RP Filter must be disabled on all interfaces!"
    echo >&2 "The RP filter feature is incompatible with policy routing"
    exit 1
  fi
done

Entonces, una de las alternativas sugeridas es usar un comando como este para evitar la subshell.

while read BLAH ; do echo $BLAH; done </root/regularfile

Entonces, me parece que también debería poder usar un comando como este para evitar la subshell y aún obtener el resultado del programa que quiero.

while read BLAH ; do echo $BLAH; done <(sysctl -a 2>/dev/null | grep '\.rp_filter')

Desafortunadamente, usar ese comando da como resultado este error.

-bash: syntax error near unexpected token `<(sysct ...

Me confundo mucho ya que esto funciona.

cat <(sysctl -a 2>/dev/null | grep '\.rp_filter')

Podría guardar la salida de ese comando en un archivo temporal y usar redireccionar el archivo temporal, pero quería evitar hacerlo.

Entonces, ¿por qué la redirección me da un error, y tengo otras opciones además de crear un archivo temporal?

Zoredache
fuente

Respuestas:

13

Te perdiste un <. Debiera ser:

while read BLAH ; do echo $BLAH; done < <(sysctl -a 2>/dev/null | grep '\.rp_filter')

Piensa en <(sysctl -a 2>/dev/null | grep '\.rp_filter')ser un archivo.

dogbane
fuente
Muchas gracias. Solo para mi edificación, ¿puedo señalarme una página de manual, ayuda o página web que documente esto? No pude hacer que Google me señalara nada útil al intentar buscar esto.
Zoredache
2
Google "sustitución de procesos". por ejemplo tldp.org/LDP/abs/html/abs-guide.html#PROCESS-SUB
dogbane
Cabe señalar que la sustitución <() usa descriptores de archivo y en algunos sistemas operativos creará y usará archivos temporales de manera transparente.
ewindisch
@Zoredache: simplemente busque <(en el manual de bash (está en "sustitución de proceso").
Gilles 'SO- deja de ser malvado'
@ewindisch, si una herramienta crea de forma transparente un archivo temporal que está bien, simplemente no quería crear uno manualmente, cuando estaba bastante seguro de que no era necesario.
Zoredache
0

Para algunas alternativas más si alguien viene aquí otra vez ...

Dependiendo del shell, probablemente podría usar set -o errexitpara que el shell padre salga cuando un comando (incluido un subshell) sale de un estado distinto de cero sin quedar atrapado en un ifbloque o un final &&o ||, como en

/bin/false || echo "ignoring error"

O puede hacer que la subshell le señale al padre usando kill y la variable de entorno $ PPID, si está disponible.

O puede mover el bloque while a una función y devolver 0/1 (devolver explícitamente 0 después del bloque while) y simplemente hacer su canalización como sysctl | grep | function || exit. Supongo que también podría poner los retornos en el bloque en línea, pero las funciones son su amigo. ;)

dannysauer
fuente