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

时间:2018-09-08 04:54:42

标签: c bash unix

因此,我有一个C程序,该程序带有一个命令行参数,并对其进行了一些处理。片刻之后,它会再次提示用户进行一些标准输入。

例如,典型用法如下:

./prac1 4
4
Enter something else: _hello_
hello

我的问题是,我如何编写一个 bash脚本,该脚本能够重新输入更多输入(通过stdin),以便在程序输出后响应程序的重新提示     输入其他内容: ?

到目前为止,我已经知道了:

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自动输入内容。我的意思是这样,这样我自己就不必手动输入。

非常感谢您。

2 个答案:

答案 0 :(得分:3)

您可以在开始运行程序时一次将所有输入字符串传递给标准输入(例如,以here document的形式);操作系统缓冲仅在接收者实际想要读取它们的情况下才提供它们。

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

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

顺便说一句,除非出口代码1非常明确地是您要捕获的唯一代码,否则只需在上面第一行的末尾添加|| exit(假设您的程序在退出时显示了诊断信息,错误;或者可能重构为shell函数die,该函数会显示警报,并使用当前退出代码然后退出。)

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

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

或随身携带

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

<<<"here string"语法仅适用于Bash。)

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

答案 1 :(得分:1)

您尚不清楚您真正想要的是什么,并且您不解释脚本的用途(因此您的问题听起来像是一些XY problem)和您的prac1程序正在做什么以及应该做什么。 / p>

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

也许bash对您来说不是正确的工具。可能您需要一些build automation工具(例如GNU makeninja)。如果您的实际目的是在编辑某些文件后重建一些代码,那是更好的选择。

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

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

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

为完整起见,我会提到expect,但我建议您不要使用它(改进prac1会更简单)。请注意,expect在终端级别上工作,并且Unix terminal emulatorsttypty很容易理解(读termios(3),{{3 }},大约pty(7)line discipline)。如果您真的想编写终端IO的代码,请考虑使用The Tty Demystified或也许ncurses之类的库。

您还可以通过阅读readline之类的书(或更新的书籍)并参考可用的ALP来了解有关Linux编程的更多信息。特别要注意的是可以通过以下方式对输入和输出进行复用的功能: syscalls(2)

  

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

您应避免这种情况。如果确实需要使用脚本来驱动其他程序,并且脚本和程序同时运行,则应考虑采用其他方法(包括使用其他脚本语言编写脚本,例如Python,AWK等)。

shell脚本的传统用法是驱动劣等程序,而不是与它们交互共存(即使使用协同过程之类的技巧也可能实现;在30多年的编程中,我从未使用过。)

当使用Shell脚本难以实现某个功能时,这是系统应该以不同的方式组织的症状。 外壳不是所有问题的答案(有时,使用其他一些工具,与该任务更相关的工具甚至是开发驱动其他进程的C程序都更简单) )。根据经验,我避免使用过于复杂的shell脚本。我可能有一些长的(但从概念上讲是简单的,因为是连续的)shell脚本。我也有一些程序(例如,在awkm4,C或Python中)生成(长)shell脚本(而poll(2)这样做已经很长时间了)。但是我避免手动编写然后维护自己复杂的shell脚本(并将它们视为设计错误的征兆)。

为了说明我的观点,makeninja(以及autoconf和其他构建自动化工具)都在驱动其他程序。原则上,从理论上讲,您可以通过编写一个怪异的Shell脚本来实现它们的目标。但是实际上,没有人这样做(并且有充分的理由:shell在实践中不是不是的通用工具)。因此,教训是:不要尝试使用bash来完成容易的操作(在我看来,这是翻译为:当您的shell脚本变得过于复杂时,抛出删除并使用或编写其他内容。

还请阅读有关scons的信息。您的脚本和C程序组合起来很不符合Unix的哲学。也许您应该有一个程序(可能是用C编写的,但是比向我们展示的prac1.c要复杂得多),或者您可能希望围绕某个运行{{ 1}}。

shell是一种方便的工具(在简单脚本中使用时),但是它是一种较差的编程语言(很难静态分析或推理;例如查看{{ 3}}研究项目,并在Unix philosophy上查看Yann Regis-Gianas FOSDEM2018演讲。 对于足够复杂的任务,您不想使用CoLiS ,而您确实想使用更好的东西,并且您应该丢弃您的变得难以理解或无法维护的shell脚本

PS。您的问题隐含了这样一个假设:prac1适用于大多数任务。但这种情况并非如此;在Linux上,您还有许多其他脚本语言,例如Parsing Posix [S]hellunix shellsPythonawkOcamlPerlIoGuile,{{ 3}},makeninjaLuaRubyPHP,...),其中许多比bash更合适,至少在 some 位。您最好选择适合您目标的工具。