如何为多次输入的C程序编写Bash脚本?

问题描述 投票:-2回答:2

所以我有一个C程序,它采用命令行参数,并用它做一些事情。片刻之后,它会重新提示用户输入一些标准输入。

例如,典型用法可能如下所示:

./prac1 4
4
Enter something else: _hello_
hello

我的问题是,如何编写一个能够重新输入更多输入(通过stdin)的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脚本使用命令行arg“4”调用可执行文件prac1。当我运行这个脚本时,在用printValue=`./$EXEC $input`执行之后,我必须在“输入其他东西:”提示后手动输入内容。这是可以预料的。

但是,我试图弄清楚如何让bash自动输入内容。我的意思是这样我自己不必手动输入它。

非常感谢你提前。

c bash unix
2个回答
3
投票

当您开始运行程序时,您可以立即传递标准输入上的所有输入字符串(例如,作为here document); OS缓冲仅在收件人实际想要读取它时才传送它们。

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.
____
)

注意我们如何使用$(...)语法而不是过时的`...`反引号语法,并避免将一个只用过一次的值(即可执行文件的名称)放入变量中。

顺便说一下,除非退出代码1非常特别是你想要捕获的唯一一个,只需在上面第一行的末尾添加|| exit(假设你的程序在退出时出现错误;或者重构为a shell函数die,它打印一个警报,然后退出当前的退出代码)。

在您的具体示例中,因为您的程序只需要一行输入,我们可以将其作为字符串传递:

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

或便携式

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

<<<"here string"语法仅限Bash。)

如果您的程序没有使用行缓冲输入表现良好,也许可以转向expect进行自动化;但是要意识到这也使得将来用户更难以在您的工具周围编写脚本。也许你想让它变得更容易,也许是通过传入命令行选项或配置文件允许用户避免交互式提示(无论如何都是邪恶的)。


1
投票

你真正想要的是不清楚,你没有解释你的脚本的目的(所以你的问题听起来像一些XY problem)和你的prac1程序正在做什么和应该做什么。

所以阅读Bash reference manual。也许你想使用read bash builtin。您还可以决定通过positional parametersgetopts builtinhere-documents的重定向向您的脚本提供一些数据。

也许bash可能不适合你。可能你想要一些build automation工具(如GNU makeninja)。如果您的实际目的是在编辑某个文件时重建某些代码,那么这是更好的方法。

查看几个小的free software项目(例如,在github上,或从您的Linux发行版),并研究他们的源代码以获得灵感。

也许将更多功能转移到prac1.c中是实现(未说明)目标的最简单方法。 prac1可能接受几个程序参数。阅读Parsing Program Arguments文档的Glibc章节。

如果要编写与正在运行的进程交互的脚本,则它很复杂。你可以考虑coprocesses

为了完整性,我会提到expect,但我建议不要在你的情况下使用它(改善prac1会更简单)。请注意,expect正在终端级别工作,Unix terminal emulatorsttys和ptys很难理解(阅读termios(3)pty(7),关于line disciplineThe Tty Demystified)。如果您真的想要编写终端IO代码,请考虑使用ncursesreadline等库。

您还可以通过阅读像ALP(或更新的东西)这样的书来了解有关Linux编程的更多信息,并参考可用的syscalls(2)。特别注意在输入和输出上多路复用的能力。 poll(2)

如何编写能够重新输入更多输入的bash脚本

你应该避免这种情况。如果你真的需要一个脚本驱动一些其他程序并同时运行脚本和程序,你应该考虑其他一些方法(包括用其他脚本语言编写脚本,例如Python,AWK,......)。

shell脚本的传统用法是驱动劣质程序,而不是与它们交互共存(即使可以通过coprocesses等技巧实现这一点;在30多年的编程中,我从未使用过它)。

如果使用shell脚本难以实现某项功能,则表明您的系统应以不同方式进行组织。 shell不是所有问题的答案(有时使用其他工具更简单,与任务更相关,甚至开发驱动其他进程的C程序)。根据经验,我避免使用过于复杂的shell脚本。我可能有一些很长的(但概念上很简单,自顺序)shell脚本。我也有一些程序(例如在awkm4,C或Python中)生成(长)shell脚本(并且autoconf很长时间都这样做)。但我避免手动编写然后维护自己复杂的shell脚本(并将其视为错误设计的症状)。

为了说明我的观点:makeninja(以及scons和其他构建自动化工具)正在推动其他程序。原则上,理论上你可以通过写一个怪异的shell脚本来实现它们的目标。但事实上,没有人这样做(并且有充分的理由:shell在实践中不是通用的工具)。所以我们的教训是:不要试图用bash做一些不容易做的事情(在我看来,转换为:当你的shell脚本变得过于复杂,扔掉它并使用或写下别的东西时)。

阅读有关Unix philosophy的信息。你的组合脚本和C程序对Unix理念很不好。也许你应该有一个程序(可能用C语言编写,但是你向我们展示的prac1.c要复杂得多),或者你想要一个运行prac1的命令的简单shell循环。

shell是一个方便的工具(当在简单的脚本中使用时),但它是一种糟糕的编程语言(并且很难进行静态分析或推理;例如查看CoLiS研究项目,并参见Yann Regis-Gianas FOSDEM2018谈话在Parsing Posix [S]hell)。对于复杂的任务,你不想使用unix shells,并且你真的想要使用更好的东西,并且当它变得不可读或不可维护时你应该丢弃你的shell脚本。

PS。你的问题暗示了bash适合大多数任务的假设。但这种情况并非如此;在Linux上,您有许多其他脚本语言,例如PythonawkOcamlPerlIoGuilemakeninjaLuaRubyPHPOcsigenHaxem4,...),其中许多比bash更适合,至少在一些利基市场。您最好选择适合您目标的工具。

© www.soinside.com 2019 - 2024. All rights reserved.