Alguém poderia me explicar o que está acontecendo nesta linha de código?

2

Eu tenho um programa C que verifica uma matriz para o número mínimo. Existe um script que irá executar o programa e fornecer casos de teste; no entanto, estou com dificuldades para descobrir o que essas linhas significam:

if ! diff -u <(echo "1 2 5" | $PROGRAM) <(echo 1); then
    echo "test failed on 1 2 5"
    ((FAILURES++))
fi

Então, eu sei que diff compara arquivos e, em seguida, -u exibirá um registro de data e hora e quais arquivos removeram a linha e quais arquivos adicionaram essa linha etc. Mas não consigo entender o que está acontecendo com "<" parte atrás do eco. Eu sei que dentro dos parênteses, (echo "1 2 5" | $ PROGRAM), aqui PROGRAM é o arquivo para executar o programa em C, meu programa obtém a saída correta para o número mínimo, mas ainda imprime falha no teste em 1 2 5 , e não consigo ver porque, não entendo a expressão na declaração if.

    
por Stuy 23.02.2018 / 22:29

3 respostas

2

Os dois argumentos <(cmd1) <(cmd2) eram novos para mim, mas aparentemente eles são substituídos por caminhos para fifos nomeados para os quais cmd1 e cmd2 escrevem. Do homem bash (1):

Process Substitution

Process substitution is supported on systems that support named
pipes (FIFOs) or the /dev/fd method of naming open files.  takes
the form of <(list) or >(list).  The process list is run with its
input or output connected to a FIFO or some file /dev/fd.  The
name of this file is passed as an argument to the current command
as the result of the expansion.  If the form is used, writing to
the file will provide input for list.  If the <(list) form is
used, the file passed as an argument be read to obtain the output
of list.

Este teste mostra os nomes do fifo:

echo <(date) <(sleep 1; date)
/dev/fd/63 /dev/fd/62

e isso imprime o resultado da leitura dos fifos:

cat <(date) <(sleep 1; date)
Fri Feb 23 14:23:41 PST 2018 
Fri Feb 23 14:23:42 PST 2018
    
por 23.02.2018 / 23:26
2

Como ninguém respondeu à pergunta (“O que está acontecendo nesta linha de código?” - "Estou com dificuldades para descobrir o que esta linha significa"):

O script está testando o programa em C. O que está fazendo é basicamente equivalente a

# Run the program with input “1 2 5” and write its output to a file.  Since the program
# is supposed to check the input for the minimum number, we expect it to output “1”.
echo "1 2 5" | $PROGRAM > file1
# Create a second file that contains the known correct output (minimum)
# for this input (i.e., “1”).
echo 1 > file2
# Compare the files.  diff’s standard output and standard error will go to the stdout
# and stderr of the script, which is the terminal unless the user does I/O redirection.
# The 'if' will test diff’s exit status.
if diff -u file1 file2
then
        # Exit status 0 means the files are identical;
        # i.e., the program’s output is correct; i.e., the test passes.  Do nothing.
        :
else
        # Exit status non-zero (probably 1) means that the files are different;
        # i.e., the program’s output is wrong; i.e., the test fails.
        echo "test failed on 1 2 5"
        ((FAILURES++))
fi
rm file1 file2

Por que o roteiro foi escrito dessa maneira?

Uma pergunta muito boa. Talvez você possa perguntar ao autor do roteiro e transmitir sua resposta para nós.

  1. Não há necessidade de usar arquivos. E, OK, eles não estão usando arquivos; eles são, como Andy Dalton e noelbk explicaram, usando substituição de processo - que é pipes, e que não é compatível com POSIX. E, sim, você precisa usar um arquivo ou um pipe para capturar a saída do programa. Mas você não precisa de nenhum arquivo ou canal para manter a saída correta. O script pode ser reescrito

    if [ "$(echo "1 2 5" | $PROGRAM)" != 1 ]
    then
            echo "test failed on 1 2 5"
            ((FAILURES++))
    fi
    

    que usa uma substituição de comando para capturar a saída do programa, e, em seguida, apenas coloca a saída correta na linha de comando if .

  2. Por que usar a opção -u de diff ?
    • Esta opção é documentada como “Saída NUM (padrão 3) linhas de contexto unificado”. Isso significa que, se você tiver dois arquivos com 100 linhas, e eles são idênticos, exceto para a linha 42, então diff -u mostrará as linhas 39-45 (três acima e três abaixo do que é diferente). Mas isso não tem sentido quando uma das entradas é conhecida por ser apenas uma linha longa, e o outro é esperado para ser apenas uma linha longa.
    • Um recurso não documentado da opção -u de diff é que mostra os tempos de modificação das entradas. Mas, no script fornecido, as entradas para diff são substituições de processo, que são tubos criados dinamicamente. Então os tempos de modificação de cada um são o tempo atual - em outras palavras, a desordem na tela.
  3. Você deve sempre citar as variáveis do shell (por exemplo, "$PROGRAM" ) a menos que você tenha uma boa razão para não.

Por que o script relata que seu programa falhou?

É impossível dizer sem ver o seu programa ou pelo menos sua saída. É possível que seu programa inclua um espaço em sua saída, ou um retorno de carro ( \r ) em vez de ou além de uma nova linha? Ou talvez até uma nova linha extra (isto é, uma linha em branco)? Faça isso

echo "1 2 5" | your_program | od -cab
(Se od informar que não reconhece todas as opções, deixe de fora o que reclama; por exemplo, -cb ou -ab .) A saída deve, obviamente, ser uma 1 e uma nova linha ( \n ).     
por 06.03.2018 / 00:00
1

A linha de código responde à pergunta: O programa definido pela variável $ PROGRAM responde a uma entrada de "1 2 5" retornando o valor 1. É uma maneira MUITO ofuscada de executar essa tarefa. Poderia ter sido escrito como:

if [ $(echo "1 2 5" | $PROGRAM) -ne 1 ] ; then

Você combinou uma segunda pergunta para esta (BTW, você deve criar uma página de pergunta separada para cada pergunta, para o benefício de outras pessoas que pesquisam, mas não perguntam). O motivo pelo qual você está obtendo uma indicação de falha, mesmo que você ache que deve ser bem-sucedida, pode ser (capturado no escuro com base na experiência pessoal) porque $PROGRAM não está enviando um caractere de nova linha após 1 .

    
por 06.03.2018 / 01:29