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

9

Quero fazer um loop sobre a saída de um comando sem criar um sub-shell ou usar um arquivo temporário.

A versão inicial do meu script era assim, mas isso não funciona, pois cria um subshell, e o exitcomando finaliza o subshell em vez do script principal necessário. Faz parte de um script muito maior para configurar o roteamento de política e interrompe a execução se detectar uma condição que fará com que o roteamento falhe.

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

Portanto, uma das alternativas sugeridas é usar um comando como este para evitar o subshell.

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

Portanto, parece-me que também devo usar um comando como este para evitar o subshell e ainda obter a saída do programa que desejo.

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 ...

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 isso.

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

Zoredache
fonte

Respostas:

13

Você perdeu um <. Deveria estar:

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')ser um arquivo.

dogbane
fonte
Muito obrigado. Apenas para minha edificação, posso apontar para uma página de manual, ajuda ou página da web que documenta isso? Não consegui que o Google me apontasse algo útil enquanto tentava pesquisar isso.
Zoredache
2
Google "substituição de processo". por exemplo, tldp.org/LDP/abs/html/abs-guide.html#PROCESS-SUB
dogbane
Deve-se observar que a substituição <() usa descritores de arquivo e, em alguns sistemas operacionais, cria e usa transparentemente arquivos temporários.
ewindisch
@ Zoredache: Basta procurar <(no manual do bash (está em "substituição de processo").
Gilles 'SO- stop be evil'
@ewindisch, se uma ferramenta cria um arquivo temporário de forma transparente, tudo bem, eu simplesmente não queria criar um manualmente, quando tinha certeza de que não precisava.
precisa saber é o seguinte
0

Para mais algumas alternativas, se alguém voltar aqui ...

Dependendo do shell, você provavelmente pode usar set -o errexitpara que o shell pai saia quando um comando (incluindo um subshell) sai diferente de zero sem ficar preso em um ifbloco ou em um final &&ou ||, como em

/bin/false || echo "ignoring error"

Ou, você pode ter o subshell sinalizar o pai usando kill e a variável de ambiente $ PPID, se disponível.

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

dannysauer
fonte