Uma maneira de ver o que está acontecendo é rastrear as chamadas do sistema envolvidas. Utilitários para fazer isso variam de acordo com a plataforma. No Solaris, você usaria treliça . No Linux (como no meu exemplo) você usaria strace .
Para rastrear, alteramos o comando usado de:
echo "test" | gpg -q -c --passphrase-fd 0 --output test.enc --yes --force-mdc test.in 2> /dev/null
para:
echo "test" | strace gpg -q -c --passphrase-fd 0 --output test.enc --yes --force-mdc test.in 2>trace_output.txt
.
A primeira coisa que se destaca como interessante (se um pouco não relacionada) é que o gpg está fazendo leituras repetidas de byte único ao tomar a senha de entrada do stdin. Às vezes, isso é um sinal revelador de código ineficiente - mas, nesse caso, provavelmente não é um grande negócio:
read(0, "t", 1) = 1
read(0, "e", 1) = 1
read(0, "s", 1) = 1
read(0, "t", 1) = 1
read(0, "\n", 1) = 1
As coisas mais relevantes sobre a saída da mensagem de log estão todas aqui:
open("/dev/tty", O_RDWR) = 3
fstat(3, {st_mode=S_IFCHR|0666, st_rdev=makedev(5, 0), ...}) = 0
ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, {B9600 opost isig icanon echo ...}) = 0
write(3, "Reading passphrase from file des"..., 45) = 45
write(3, " \n", 7) = 7
É tudo o que ouvimos sobre o descritor de arquivos 3 até sair (não está explicitamente fechado).
Olhando cada um deles por sua vez:
-
open("/dev/tty", O_RDWR) = 3
Isso está abrindo o arquivo / dev / tty, tanto para leitura quanto para escrita. O valor de retorno (um novo descritor de arquivo para uso posterior) é 3.
/ dev / tty é um sinônimo para o atual terminal de controle . Você pode ver o dispositivo que está sendo efetivamente referenciado por este arquivo especial, executando
$ tty
-
fstat(3, {st_mode=S_IFCHR|0666, st_rdev=makedev(5, 0), ...}) = 0
Isto é usado pelo gpg para descobrir sobre o arquivo que acabou de abrir com o descritor de arquivo 3. O material entre chaves é o que é retornado (um stat de estrutura preenchido, com o 5, 0 indicando que este é um arquivo especialmente especial ).
-
ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, {B9600 opost isig icanon echo ...}) = 0
Isto está manipulando atributos do terminal de controle, antes da saída.
-
write(3, "Reading passphrase from file des"..., 45) = 45
write(3, " \n", 7) = 7
Estes são mais diretos. O gpg escreve com sucesso esse texto (parte do qual foi abreviado na saída strace) para o terminal.
Então - esta é sua resposta. gpg está escrevendo esta mensagem de log diretamente para / dev / tty (sinônimo para o terminal de controle), então você não será capaz de redirecioná-la da mesma maneira para stdout ou stderr.
Existe uma maneira de contornar isso. Você pode desconectar o terminal de controle antes de executar o gpg.
Aqui está um pequeno programa que faz exatamente isso:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
int main(int argc, char* argv[])
{
int rc, fd;
if (argc != 2)
{
fprintf(stderr,
"Provide command line arg to execute after TIOCNOTTY\n");
return EXIT_FAILURE;
}
fd = open("/dev/tty", O_RDWR);
if (fd < 0)
{
fprintf(stderr,
"Failed to open controlling terminal: %s\n",
strerror(errno));
return EXIT_FAILURE;
}
rc = ioctl(fd, TIOCNOTTY);
if (rc == -1)
{
fprintf(stderr,
"Failed TIOCNOTTY ioctrl: %s\b",
strerror(errno));
return EXIT_FAILURE;
}
return system(argv[1]);
}
Deveria haver um utilitário existente para fazer o acima, mas não consegui encontrar um.
Se você fosse compilar esse código, chame o executável resultante notty
, então você poderia fazer isso:
echo "test" | notty "gpg -q -c --passphrase-fd 0 --output test.enc --yes --force-mdc test.in"
Isso deve suprimir a mensagem, mas mantenha seu stdout e stderr intactos. Não está claro o que mais seria suprimido (você precisaria olhar para a fonte gpg para ver o que mais é produzido dessa maneira).