Percebi um antipadrão estranho em alguns scripts de CI que assumi, que basicamente se resume a este código verificando se um arquivo específico está presente em um pacote:
dpkg --contents some.deb > contents.txt
grep --quiet foo contents.txt
Eu tentei o refator óbvio de dpkg --contents some.deb | grep --quiet foo
, mas continuo recebendo este erro:
dpkg-deb: erro: o subprocesso tar foi morto por sinal (tubo quebrado)
De mais algumas investigações, este é definitivamente um problema de tempo. Se eu usar um regex que corresponda no início do fluxo de entrada, recebo o erro, mas se eu usar um regex que corresponda especificamente a uma linha tardia, ele será bem-sucedido.
A conclusão mais óbvia é que dpkg
(ou possivelmente tar
) faz algo errado com o SIGPIPE. Isso é um problema conhecido?
Plataforma:
# lsb_release --all
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 18.04.6 LTS
Release: 18.04
Codename: bionic
# dpkg --version
Debian 'dpkg' package management program version 1.19.0.5 (amd64).
This is free software; see the GNU General Public License version 2 or
later for copying conditions. There is NO warranty.
# tar --version
tar (GNU tar) 1.29
Copyright (C) 2015 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Written by John Gilmore and Jay Fenlason.
dpkg
usatar
para listar o conteúdo do pacote. Quandotar
não é possível processar um arquivo na íntegra, indica um erro, e é isso quedpkg
está relatando. Ambos os comandos esperam que a incapacidade de concluir sua tarefa seja um erro e agem de acordo.Você pode evitar isso garantindo que
grep
leia toda a sua entrada antes de sair:(em vez de
-q
, que sai assim que corresponde).Você também pode usar um comando que absorverá a saída de
dpkg
antes de passar tudo paragrep
, sem gerar um erro no SIGPIPE.perl
é tal comando:As
perl
opções significam:-0777
slurp toda a entrada em uma "linha"-p
leia cada "linha" de stdin e imprima para stdout-e1
avalie a expressão dada (1
) para cada "linha" de entrada.