#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