Как написать Bash-скрипт для программы на C, которая принимает ввод несколько раз? - PullRequest
0 голосов
/ 08 сентября 2018

Итак, у меня есть программа на C, которая принимает аргумент командной строки и что-то делает с ним. Через некоторое время пользователь снова запрашивает стандартный ввод.

Например, типичное использование может выглядеть так:

./prac1 4
4
Enter something else: _hello_
hello

Мой вопрос: как мне написать bash-скрипт , который может повторно вводить больше входных данных (через стандартный ввод данных), чтобы ответить на повторный запрос программы после выхода программы Введите что-то еще:

Пока у меня есть это:

cc=gcc
EXEC=prac1
SRC=prac1.c
input="4"

printValue=`./$EXEC $input`
if [ "$?" == '1' ];
then
    echo "Error"
    exit
fi
echo "printValue = $printValue"

prac1 выше относится к следующему коду:

int main(int argc, char** argv) {
    char* input[70];
    printf("%c\n", argv[1][0];
    fflush(stdin);
    printf("Enter something else: ");
    fscanf(stdin, "%s", input);
    printf("%s\n", input);
}

Скрипт bash вызывает исполняемый файл prac1 с командной строкой arg "4". Когда я запускаю этот скрипт, после того, как он выполняется с printValue=`./$EXEC $input`, я должен вручную что-то набрать после приглашения «Введите что-то еще:». Этого следовало ожидать.

Тем не менее, я пытаюсь выяснить, как заставить bash ввести что-то автоматически. Я имею в виду, что мне не нужно вводить его вручную.

Заранее большое спасибо.

Ответы [ 2 ]

0 голосов
/ 08 сентября 2018

Вы можете сразу передать все входные строки на стандартный ввод при запуске вашей программы (например, как здесь документ ); буферизация ОС берет на себя доставку только тогда, когда получатель действительно хочет прочитать ее.

printValue=$(./prac1 "$input"<<\____
first answer
Here's my answer to the second prompt.
If the script reads multiple lines of input
until EOF at any point, that of course will
consume all of the remaining here document.
____
)

Обратите внимание, как мы используем синтаксис $(...) вместо устаревшего синтаксиса `...` backtick, и избегайте ввода в переменную значения, которое в любом случае используется только один раз (то есть имя вашего исполняемого файла) .

В качестве отступления, если только код выхода 1 не является единственным, который вы хотите перехватить, просто добавьте || exit в конце первой строки выше (при условии, что ваша программа печатает диагностику, когда она завершается с ошибкой; или, возможно, рефакторинг в функцию оболочки die, которая печатает предупреждение и , затем завершает работу с текущим кодом выхода).

В вашем конкретном примере, поскольку вашей программе требуется только одна строка ввода, мы можем передать ее в виде строки:

printValue=$(./prac1 "$input" <<<"something else")

или переносимо с

printValue=$(echo "something else" | ./prac1 "$input")

(синтаксис <<<"here string" только Bash.)

Если ваша программа плохо себя ведет со строковым буферизованным вводом, возможно, обратитесь к expect для ее автоматизации; но поймите, что в будущем пользователям будет сложнее писать сценарии вокруг вашего инструмента. Возможно, вы хотите сделать это проще, возможно, позволив пользователям избегать интерактивных подсказок (которые в любом случае являются злыми), передавая параметры командной строки или файл конфигурации.

0 голосов
/ 08 сентября 2018

То, что вы действительно хотите, неясно, и вы не объясняете цель своего сценария (поэтому ваш вопрос звучит как какая-то проблема XY ) и что делает и должна делать ваша программа prac1.

Итак прочитайте справочное руководство Bash .Возможно, вы хотите использовать встроенную read bash .Вы также можете решить передать некоторые данные в ваш скрипт через позиционные параметры или getopts встроенный или перенаправление из here-документов .

Может быть, bash не может быть правильным инструментом для вас.Возможно, вам нужен инструмент для автоматизации сборки (например, GNU make или ninja ).Если ваша настоящая цель состоит в том, чтобы перестроить некоторый код после того, как какой-либо файл был отредактирован, то это лучший способ.

Просмотрите несколько небольших свободных программ проектов (например, на github). (или из вашего дистрибутива Linux) и изучите их исходный код для вдохновения.

Возможно, добавление большего количества функций в ваши prac1.c - это самый простой способ достижения ваших (неустановленных) целей.prac1 может принимать нескольких программных аргументов.Прочтите Аргументы программы синтаксического анализа главы Glibc документации.

Если вы хотите закодировать скрипт, который взаимодействует с running процесс, это сложно.Вы можете рассмотреть сопроцессы .

Для полноты я упомяну expect, но я рекомендую не использовать его в вашем случае (было бы проще улучшить prac1).Обратите внимание, что expect работает на уровне терминала, а эмуляторы терминала Unix , tty s и pty s сложны для понимания (читайте termios (3) , pty (7) , около линейная дисциплина и Tty Demysified ).Если вы действительно хотите кодировать терминальный ввод-вывод, рассмотрите возможность использования таких библиотек, как ncurses или, возможно, readline .

. Вы также можете узнать больше о программировании Linux, прочитав книгу типа ALP (или что-то более новое) и обратитесь к имеющимся системным вызовам (2) .Обратите внимание, в частности, на возможность мультиплексирования при вводе и выводе, например, с помощью poll (2) .

, как мне написать bash-скрипт, способный повторно вводить больше ввода

Вы должны избежать этой ситуации .Если вам действительно нужен сценарий, управляющий какой-либо другой программой, и сценарий и программа выполняются вместе, вам следует рассмотреть другой подход (включая написание сценария на каком-либо другом языке сценариев, например Python, AWK, ...).

Традиционное использование сценариев оболочки состоит в том, чтобы управлять низшими программами , а не сосуществовать с ними в интерактивном режиме (даже если это возможно с помощью таких хитростей, как сопроцессы; в течение более 30 летпрограммирование, я никогда не использовал это).

Когда функцию трудно реализовать с помощью сценария оболочки, это признак того, что ваша система должна быть организована по-другому. Оболочка является , а не ответом на все проблемы (иногда проще использовать какой-либо другой инструмент, более соответствующий задаче, или даже разработать вашу программу на C, управляющую другими процессами).Как правило, я избегаю слишком сложных сценариев оболочки.У меня могут быть длинные (но концептуально простые, начиная с последовательных) сценарии оболочки.У меня также есть некоторые программы (например, в awk, m4, C или Python), генерирующие (длинные) сценарии оболочки (а autoconf делает это долгое время).Но я избегаю писать вручную, а затем поддерживаю сложные сценарии оболочки (и рассматриваю их как симптом чего-то неправильно спроектированного).

Чтобы проиллюстрировать мою точку зрения выше: make и ninja (а также scons и другие инструменты автоматизации сборки) управляют другими программами. В принципе, вы можете теоретически достичь их целей, написав чудовищный скрипт, делающий то же самое. Но на самом деле никто этого не делал (и не зря: оболочка не универсальный инструмент на практике). Итак, урок: не пытайтесь делать с bash то, что не было предназначено сделать легко (и, по моему мнению, это означает: когда ваш сценарий оболочки становится слишком сложным, выбросьте его и используйте или напишите что-нибудь еще).

Читайте также о философии Unix . Ваш комбинированный скрипт и программа на Си плохо пахнут против этой философии Unix. Возможно, у вас должна быть одна программа (вероятно, написанная на C, но гораздо более сложная, чем prac1.c, которую вы нам показываете), или, возможно, вы хотите простой цикл оболочки вокруг какой-то команды, выполняющей prac1.

Оболочка является удобным инструментом (при использовании в простых сценариях), но это плохой язык программирования (и его очень сложно статически анализировать или рассуждать; посмотрите, например, на CoLiS исследовательский проект, и посмотрите выступление Янн Реджис-Джианас FOSDEM2018 по Парсинг Posix [S] ад ). Для достаточно сложных задач вы не хотите, чтобы использовали оболочки Unix , и вы действительно хотите использовать что-то лучше, и вы должны выбросить ваш сценарий оболочки, когда он становится нечитаемым или не поддерживаемым .

PS. Ваш вопрос неявно выдвигает гипотезу, что bash подходит для большинства задач. Но это не так; в Linux у вас есть много других языков сценариев, например, Python , awk, Ocaml , Perl , Io , Guile , make, ninja, Lua , Ruby , PHP , Ocsigen , Haxe , m4, ...), многие из них больше подходят, чем bash, по крайней мере в некоторых нишах. Вам лучше выбрать инструмент, подходящий для ваших целей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...