Iterar sobre a saída de um comando no bash sem um subshell

9

Eu quero repetir a saída de um comando sem criar um sub-shell ou usar um arquivo temporário.

A versão inicial do meu script ficou assim, mas isso não funciona, pois cria um subshell, e o comando exit finaliza o subshell em vez do script principal, que é necessário. Ele faz parte de um script muito maior para configurar o roteamento de políticas e interrompe a execução se detectar uma condição que causará falha no roteamento.

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

Então, uma das alternativas sugeridas é usar um comando como esse para evitar a sub-camada.

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

Então, parece-me que eu também deveria poder usar um comando como esse para evitar o subshell e ainda obter a saída do programa que eu quero.

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

Infelizmente, o uso desse comando resulta nesse erro.

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

Eu fico realmente confuso, pois isso funciona.

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

Eu poderia salvar a saída desse comando em um arquivo temporário e usar o redirecionamento no arquivo temporário, mas queria evitar fazer isso.

Então, por que o redirecionamento está me dando um erro, e eu tenho outras opções além de criar um arquivo temporário?

    
por Zoredache 14.01.2011 / 18:40

2 respostas

13

Você perdeu um < . Deve ser:

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

Pense em <(sysctl -a 2>/dev/null | grep '\.rp_filter') como um arquivo.

    
por 14.01.2011 / 18:50
0

Para mais algumas alternativas, se alguém vier aqui de novo ...

Dependendo do shell, você provavelmente pode usar set -o errexit para que o shell pai seja encerrado quando um comando (incluindo um subshell) sair diferente de zero sem ficar preso em um bloco if ou em um && ou% final||, como em

/bin/false || echo "ignoring error"

Ou, você pode fazer com que o subshell sinalize o pai usando kill e a variável de ambiente $ PPID, se disponível.

Ou você poderia mover o bloco while para uma função e retornar 0/1 (explicitamente retornar 0 após o bloco while) e apenas fazer o seu pipeline como sysctl | grep | function || exit . Eu suponho que você poderia colocar os retornos no bloco inline, também, mas as funções são suas amigas. ;)

    
por 06.10.2013 / 20:39