* NEWS: Mention the bug fix.
* src/comm.c (usage): Remove mention that FILE1 and FILE2 cannot both be
standard input.
(compare_files): Only close standard input once.
* doc/coreutils.texi (comm invocation): Document the behavior of
'comm - -' which is not portable to all implementations.
* tests/comm/dash-dash.sh: New file.
* tests/misc/comm.pl: Move to tests/comm/comm.pl.
* tests/local.mk (all_tests): Add the new test. Rename the existing
test.
* Noteworthy changes in release ?.? (????-??-??) [?]
+** Bug fixes
+
+ 'comm - -' no longer closes standard input twice. Previously it would
+ mistakenly exit with a nonzero status.
+ [This bug was present in "the beginning".]
+
* Noteworthy changes in release 9.11 (2026-04-20) [stable]
@end table
+POSIX leaves the behavior undefined when @var{file1} and @var{file2}
+both refer to standard input, i.e., when both are @samp{-}. GNU
+@command{comm} reads the first line as if it came from @var{file1} and
+the second as if it were from @var{file2}, and continues alternating in
+this manner until the end of file is reached.
+
@node ptx invocation
@section @command{ptx}: Produce permuted indexes
"), stdout);
fputs (_("\
\n\
-When FILE1 or FILE2 (not both) is -, read standard input.\n\
+When FILE1 or FILE2 is -, read standard input.\n\
"), stdout);
fputs (_("\
\n\
}
}
- for (int i = 0; i < 2; i++)
+ /* Avoid closing standard input twice when invoking 'comm - -'. */
+ const int n_streams = 2 - (streams[0] == streams[1]);
+ for (int i = 0; i < n_streams; i++)
if (fclose (streams[i]) != 0)
error (EXIT_FAILURE, errno, "%s", quotef (infiles[i]));
--- /dev/null
+#!/bin/sh
+# Test that 'comm - -' works.
+
+# Copyright (C) 2026 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ comm
+
+printf '1\n\t2\n\t\t3\n4\n\t5\n\t\t6\n7\n\t8\n\t\t9\n' >exp \
+ || framework_failure_
+
+# In coreutils 9.11 and earlier, running 'comm - -' would close
+# standard input twice, leading to an incorrect exit status.
+seq 9 | sed 'n;n;p' | timeout 10 comm - - >out 2>err || fail=1
+compare exp out || fail=1
+compare /dev/null err || fail=1
+
+Exit $fail
tests/cksum/cksum-base64.pl \
tests/cksum/cksum-base64-untagged.sh \
tests/cksum/cksum-raw.sh \
- tests/misc/comm.pl \
+ tests/comm/comm.pl \
+ tests/comm/dash-dash.sh \
tests/csplit/csplit.sh \
tests/csplit/csplit-1000.sh \
tests/csplit/csplit-heap.sh \