On 09/01/2025 15:34, Daniel Hofstetter wrote:
Hi,

While experimenting with csplit I noticed the following behavior: if
the input is empty, an empty xx00 split file is created:

$ printf "" | csplit - 5
csplit: input disappeared
$ ls xx00
xx00

However, if the input is not empty, no such file is created:

$ printf "a" | csplit - 5
csplit: ‘5’: line number out of range
1
$ ls xx00
ls: cannot access 'xx00': No such file or directory

Is this a bug or a feature?

Looks like a bug.
I can't think why the "input disappeared" case is handled separately.
I'll push the attached later to treat it like the second case above.

cheers,
Pádraig
From 268b40b276e43561006344e6980aa628b96f842a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C3=A1draig=20Brady?= <p...@draigbrady.com>
Date: Thu, 9 Jan 2025 19:29:01 +0000
Subject: [PATCH] csplit: avoid extraenous output files given empty input

* src/csplit.c (get_first_line_in_buffer): Don't exit here
upon empty input, rather indicate no input in the return
to let callers handle in a more consistent fashion.
* NEWS: Mention the bug fix.
* tests/csplit/csplit.sh: Add a test case.
Reported by Daniel Hofstetter.
---
 NEWS                   |  3 +++
 src/csplit.c           | 11 +++++++----
 tests/csplit/csplit.sh | 10 ++++++++++
 3 files changed, 20 insertions(+), 4 deletions(-)

diff --git a/NEWS b/NEWS
index 793745de6..4a0c1da98 100644
--- a/NEWS
+++ b/NEWS
@@ -11,6 +11,9 @@ GNU coreutils NEWS                                    -*- outline -*-
   cp,mv --update no longer overrides --interactive or --force.
   [bug introduced in coreutils-9.3]
 
+  csplit no longer creates empty files given empty input.
+  [This bug was present in "the beginning".]
+
   ls and printf fix shell quoted output in the edge case of escaped
   first and last characters, and single quotes in the string.
   [bug introduced in coreutils-8.26]
diff --git a/src/csplit.c b/src/csplit.c
index c65e3d418..9119dcf5a 100644
--- a/src/csplit.c
+++ b/src/csplit.c
@@ -494,13 +494,14 @@ load_buffer (void)
     }
 }
 
-/* Return the line number of the first line that has not yet been retrieved. */
+/* Return the line number of the first line that has not yet been retrieved.
+   Return 0 if no lines available.  */
 
 static intmax_t
 get_first_line_in_buffer (void)
 {
   if (head == nullptr && !load_buffer ())
-    error (EXIT_FAILURE, errno, _("input disappeared"));
+    return 0;
 
   return head->first_available;
 }
@@ -627,7 +628,7 @@ write_to_file (intmax_t last_line, bool ignore, int argnum)
 
   first_line = get_first_line_in_buffer ();
 
-  if (first_line > last_line)
+  if (! first_line || first_line > last_line)
     {
       error (0, 0, _("%s: line number out of range"),
              quote (global_argv[argnum]));
@@ -698,7 +699,9 @@ process_line_count (const struct control *p, intmax_t repetition)
   if (no_more_lines () && suppress_matched)
     handle_line_error (p, repetition);
 
-  linenum = get_first_line_in_buffer ();
+  if (!(linenum = get_first_line_in_buffer ()))
+    handle_line_error (p, repetition);
+
   while (linenum++ < last_line_to_save)
     {
       struct cstring *line = remove_line ();
diff --git a/tests/csplit/csplit.sh b/tests/csplit/csplit.sh
index 021b08ae2..e3c16c1cc 100755
--- a/tests/csplit/csplit.sh
+++ b/tests/csplit/csplit.sh
@@ -100,4 +100,14 @@ printf 'x%8199s\nx\n%8199s\nx\n' x x > in
 csplit in '/x\{1\}/' '{*}' > /dev/null || fail=1
 cat xx?? | compare - in || fail=1
 
+# Ensure file not created for empty input
+# which was the case with coreutils <= 9.5
+rm -f in && touch in || framework_failure_
+csplit in 5 > out 2> err && fail=1
+test -f xx00 && fail=1
+cat <<\EOF > experr
+csplit: '5': line number out of range
+EOF
+compare experr err || fail=1
+
 Exit $fail
-- 
2.47.1

Reply via email to