разница в двух программах с одинаковым вводом?

#shell #sh

#оболочка #sh

Вопрос:

 #!bin/sh

i=0;
while read inputline
do
        array[$i]=$inputline;
        i=`expr $i   1`
done

j=i;

./a.out > test/temp;
while [$i -gt 0]
do
echo ${array[$i]}
i=`expr $i -  1`;
done

./test > test/temp1;
while [$j -gt 0]
do
echo ${array[$j]}
j=`expr $j -  1`;
done

diff test/temp1 test/temp
  

Что не так с приведенным выше кодом? По сути, то, что он должен делать, это принимать некоторый ввод из stdin, а затем предоставлять один и тот же ввод двум отдельным программам, а затем помещать их вывод в другой файл, а затем дифференцировать их. Почему это не работает?

Комментарии:

1. возможная опечатка: «test / temp2» никогда не создается скриптом, первый выводит на «test / temp», а второй выводит на «test / temp1». Разница между одним файлом, который существует, и тем, которого нет. Если это ваша ошибка, добро пожаловать. В противном случае, пожалуйста, отредактируйте.

2. Что заставляет вас думать, что ./a.out и ./test считывают строки, которые повторяются в циклах while?

3. опечатка не была проблемой, и что вы имеете в виду, читая строки? Я не программировал в оболочке более года, это просто для того, чтобы помочь мне выполнить задание на c

4. @temporary: вы написали ... and then provide the smae input to two seperate prgorams .

5. знаете ли вы лучший способ, которым я могу это сделать?, По сути, у меня есть две программы, которые запрашивают у пользователя ввод, в каждой строке, которую я ввожу, они что-то выводят, и я хочу ввести ввод один раз и просто изменить вывод?

Ответ №1:

Я вижу несколько вещей, которые могут быть проблемами.

Во-первых, обычно путь к sh — это /bin/sh . Я бы ожидал, что линия shebang будет примерно такой:

 #!/bin/sh
  

Однако это может и не вызывать ошибку, если вы вызываете sh из командной строки.

Во-вторых, выходные данные из ваших циклов while должны быть перенаправлены в ваши исполняемые файлы:

 {
    while [ $i -lt $lines ]
    do
        echo ${array[$i]}
        i=`expr $i    1`;
    done
} | ./a.out > test/temp;
  

Примечание: я тестировал это на Mac OS X и Linux, и sh имеет псевдоним bash в обеих операционных системах. Я не совсем уверен, что эта конструкция работает в обычном старом sh.

В-третьих, индексация отключена в ваших циклах while: она должна идти от 0 до $ i — 1 (или от $ i — 1 до 0). Как написано в вашем примере, он идет от $ i до 1.

Наконец, «test» используется как в качестве имени вашего исполняемого файла, так и в качестве имени выходного каталога. Вот что у меня получилось:

 #!/bin/sh

lines=0;
while read inputline
do
        array[$lines]=$inputline;
        lines=`expr $lines   1`
done

i=0
{
    while [ $i -lt $lines ]
    do
        echo ${array[$i]}
        i=`expr $i    1`;
    done
} | ./a.out > test/temp;

i=0
{
    while [ $i -lt $lines ]
    do
        echo ${array[$i]}
        i=`expr $i    1`;
    done
} | ./b.out > test/temp1;

diff test/temp1 test/temp
  

Другой способ сделать то, что вы хотите, — сохранить ваши тестовые входные данные в файле и просто использовать конвейер для подачи входных данных в программы. Например, если ваши входные данные хранятся в input.txt тогда вы можете сделать это:

 cat input.txt | a.out > test/temp
cat input.txt | b.out > test/temp1
diff test/temp test/temp1
  

Комментарии:

1. На самом деле вам не нужны брекеты. Это подойдет: while ... done | ./a.out > tmp

2. Спасибо за совет; удаление фигурных скобок сделало бы сценарий намного чище.

3. С фигурными скобками или без них то, что вы делаете, будет хорошо работать с Bourne или Korn shell.

Ответ №2:

Другой подход заключается в захвате стандартного ввода следующим образом:

 #!/bin/sh
input=$(cat -)
printf "%s" "$input" | ./a.out > test/temp
printf "%s" "$input" | ./test  > test/temp1
diff test/temp test/temp1
  

или, используя замену процесса bash и здесь-строки:

 #!/bin/bash
input=$(cat -)
diff <(./a.out <<< "$input") <(./test <<< "$input")
  

Ответ №3:

Что не так?

Точки с запятой не нужны, хотя они не наносят вреда.

Начальный цикл ввода выглядит нормально.

Назначение j=i сильно отличается от j=$i .

Вы запускаете программу ./a.out , не предоставляя ей никаких входных данных.

Затем у вас есть цикл, который должен был повторять ввод. Он предоставляет ввод в обратном направлении по сравнению с тем, как он был прочитан.

Вы повторяете выполнение программы ./test без ввода каких-либо входных данных, за которым следует цикл повторения, который должен был повторять ввод, но этот сбой происходит из-за неправильного назначения.

Затем вы запускаете diff два вывода, полученных из неопределенных входных данных.

Вы не очищаете временные файлы.

Как это сделать

Этот сценарий прост — за исключением того, что он гарантирует, что временные файлы будут очищены.

 tmp=${TMPDIR:-/tmp}/tester.$$
trap "rm -f $tmp.?; exit 1" 0 1 2 3 13 15

cat - > $tmp.1
./a.out < $tmp.1 > $tmp.2
./test  < $tmp.1 > $tmp.3
diff $tmp.2 $tmp.3

rm -f $tmp.?
trap 0
exit 0
  

Первым шагом является запись входных данных в файл $tmp.1 . Затем запустите две тестовые программы, записывая выходные данные в файлах $tmp.2 и $tmp.3 . Затем возьмите разницу между двумя файлами.

Первая trap строка гарантирует, что временные файлы будут удалены при выходе из оболочки или при получении сигнала от набора { HUP, INT, QUIT, PIPE, TERM } . Вторая trap строка отменяет ловушку «выхода», чтобы скрипт мог успешно завершить работу. (Вы можете передать статус выхода diff вызывающей программе (оболочке), записав ее статус выхода status=$? и затем используя exit $status .)

Ответ №4:

Если все, что вы хотите сделать, это предоставить один и тот же стандартный идентификатор двум программам, вы можете использовать подстановку процессов вместе tee . Предполагая, что вы можете cat вводить данные из файла (или просто используя tee часть, если хотите, чтобы она была интерактивной), вы могли бы использовать что-то вроде этого:

 cat input | tee >(./p1 > p1.out) >(./p2 > p2.out) amp;amp; diff p1.out p2.out