有人可以向我解释一下这行代码中发生了什么吗?

有人可以向我解释一下这行代码中发生了什么吗?

我有一个 C 程序,用于检查数组中的最小数字。有一个脚本将运行该程序并为其提供测试用例;但是,我正在努力找出这些行的含义:

if ! diff -u <(echo "1 2 5" | $PROGRAM) <(echo 1); then
    echo "test failed on 1 2 5"
    ((FAILURES++))
fi

所以我知道diff比较文件,然后-u会显示时间戳,哪些文件删除了哪行,哪些文件添加了哪行,等等。但我似乎无法理解回显后面的“<”部分发生了什么。我知道在括号内,(echo "1 2 5" | $PROGRAM),这里 PROGRAM 是执行 C 程序的文件,我的程序获得最小数量的正确输出,但它仍然打印 test failed on 1 2 5 ,我不明白为什么,因为我不明白 if 语句中的表达式。

答案1

这两个<(cmd1) <(cmd2)参数对我来说是新的,但显然它们被替换为命名 fifo 的路径cmd1cmd2写入。来自 man bash(1):

Process Substitution

Process substitution is supported on systems that support named
pipes (FIFOs) or the /dev/fd method of naming open files.  takes
the form of <(list) or >(list).  The process list is run with its
input or output connected to a FIFO or some file /dev/fd.  The
name of this file is passed as an argument to the current command
as the result of the expansion.  If the form is used, writing to
the file will provide input for list.  If the <(list) form is
used, the file passed as an argument be read to obtain the output
of list.

此测试显示 fifo 名称:

echo <(date) <(sleep 1; date)
/dev/fd/63 /dev/fd/62

这会打印读取 fifo 的结果:

cat <(date) <(sleep 1; date)
Fri Feb 23 14:23:41 PST 2018 
Fri Feb 23 14:23:42 PST 2018

答案2

由于没有人回答这个问题(“这行代码发生了什么?”——“我正在努力找出这行代码的含义”):

该脚本正在测试 C 程序。它所做的基本上相当于

# Run the program with input “1 2 5” and write its output to a file.  Since the program
# is supposed to check the input for the minimum number, we expect it to output “1”.
echo "1 2 5" | $PROGRAM > file1
# Create a second file that contains the known correct output (minimum)
# for this input (i.e., “1”).
echo 1 > file2
# Compare the files.  diff’s standard output and standard error will go to the stdout
# and stderr of the script, which is the terminal unless the user does I/O redirection.
# The `if` will test diff’s exit status.
if diff -u file1 file2
then
        # Exit status 0 means the files are identical;
        # i.e., the program’s output is correct; i.e., the test passes.  Do nothing.
        :
else
        # Exit status non-zero (probably 1) means that the files are different;
        # i.e., the program’s output is wrong; i.e., the test fails.
        echo "test failed on 1 2 5"
        ((FAILURES++))
fi
rm file1 file2

剧本为什么这么写?

一个非常好的问题。也许你可以询问剧本的作者并将他们的答案转达给我们。

  1. 无需使用文件。而且,好吧,他们不使用文件;而是使用文件。他们是,如安迪道尔顿诺尔贝克已经解释过,使用进程替换——这是管道,并且不符合 POSIX 标准。是的,您需要使用文件或管道来捕获程序的输出。但是您不需要文件或管道来保存正确的输出。脚本可以重写

    if [ "$(echo "1 2 5" | $PROGRAM)" != 1 ]
    then
            echo "test failed on 1 2 5"
            ((FAILURES++))
    fi
    

    它使用一个命令替换以捕获程序的输出,然后将正确的输出放在if命令行上。

  2. 为什么要使用-u的选项diff
    • 此选项被记录为“输出 NUM(默认 3)行统一上下文”。因此,这意味着,如果您有两个 100 行长的文件,并且除了第 42 行之外它们是相同的,那么diff -u将显示第 39-45 行(不同的行上方三行和下方三行)。但是,当已知其中一个输入只有一行长,而另一个输入预计也只有一行长时,这是没有意义的。
    • -u选项的一个未记录的功能diff 是它显示输入的修改时间。但是,在给定的脚本中,输入diff是进程替换,它们是动态创建的管道。因此,每个内容的修改时间都是当前时间,换句话说,就是屏幕上的混乱时间。
  3. 您应该始终引用 shell 变量(例如"$PROGRAM"),除非您有充分的理由不这样做。

为什么脚本报告您的程序失败?

如果没有看到你的程序,或者至少是它的输出,就不可能知道。您的程序是否可能在其输出中包含空格或回车符 ( \r),而不是换行符或除了换行符之外?或者甚至可能是一个额外的换行符(即空行)?做这个

回声“1 2 5”|你的程序| OD-驾驶室
(如果od报告它无法识别所有选项,请忽略它所抱怨的选项;例如,-cb-ab。)当然,输出应该是 a1和换行符 ( \n)。

答案3

这行代码回答了这个问题:变量 $PROGRAM 定义的程序是否通过返回值 1 来响应“1 2 5”的输入。这是执行该任务的一种非常混乱的方式。它可以写成:

if [ $(echo "1 2 5" | $PROGRAM) -ne 1 ] ; then

您将第二个问题合并到了第一个问题中(顺便说一句,您确实应该为每个问题创建一个单独的问题页面,以方便搜索但不询问的其他人)。尽管您认为应该成功,但您收到失败指示的原因可能是(根据个人经验在黑暗中拍摄)因为$PROGRAM1.

相关内容