]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
cut: support -F as an alias for -f -w -O ' '
authorPádraig Brady <P@draigBrady.com>
Fri, 13 Mar 2026 19:48:05 +0000 (19:48 +0000)
committerPádraig Brady <P@draigBrady.com>
Sun, 5 Apr 2026 12:15:56 +0000 (13:15 +0100)
To improve compatibility with toybox/busybox scripts.

doc/coreutils.texi
src/cut.c
tests/cut/cut.pl

index 00244655bafc9c7100c038edb8d725e51cde0e85..14ba21ab931c4a1ea202c691e7575d9c30f58c26 100644 (file)
@@ -6208,10 +6208,11 @@ join -a1 -o 1.2,1.1 - /dev/null # reorder the first two fields
 @end verbatim
 @end example
 
-@optItem{cut,-d,@w{ }@var{input_delim_byte}}
-@optItemx{cut,--delimiter,=@var{input_delim_byte}}
-With @option{-f}, use the first byte of @var{input_delim_byte} as
-the input fields separator (default is TAB).
+@optItem{cut,-F,}
+Like the @option{-f,--fields} option, but also implies
+@option{-w} and @option{--output-delimitor=' '}.
+I.e., fields are separated by runs of blank characters,
+and output fields are separated by a single ASCII space.
 
 @optItem{cut,-n,}
 @optItemx{cut,--no-partial,}
index f944748894f1b482e59b610ab2065b119e3da51c..80b4aa84b35747997bdaf66ebcd5652a36be2e33 100644 (file)
--- a/src/cut.c
+++ b/src/cut.c
@@ -119,6 +119,9 @@ static bool whitespace_delimited;
 /* If true, ignore leading and trailing whitespace in -w mode.  */
 static bool trim_outer_whitespace;
 
+/* If true, default the output delimiter to a single space.  */
+static bool space_output_delimiter_default;
+
 enum whitespace_option
 {
   WHITESPACE_OPTION_TRIMMED
@@ -207,6 +210,10 @@ Print selected parts of lines from each FILE to standard output.\n\
   -f, --fields=LIST\n\
          select only these fields;  also print any line that contains\n\
          no delimiter character, unless the -s option is specified\n\
+"));
+      oputs (_("\
+  -F LIST\n\
+         like -f, but also implies -w and -O ' '\n\
 "));
       oputs (_("\
   -n, --no-partial\n\
@@ -234,7 +241,7 @@ Print selected parts of lines from each FILE to standard output.\n\
       oputs (VERSION_OPTION_DESCRIPTION);
       fputs (_("\
 \n\
-Use one, and only one of -b, -c or -f.  Each LIST is made up of one\n\
+Use one, and only one of -b, -c, -f or -F.  Each LIST is made up of one\n\
 range, or many ranges separated by commas.  Selected input is written\n\
 in the same order that it is read, and is written exactly once.\n\
 "), stdout);
@@ -914,6 +921,7 @@ main (int argc, char **argv)
   int optc;
   bool ok;
   bool delim_specified = false;
+  bool whitespace_delimited_specified = false;
   char *spec_list_string = NULL;
 
   initialize_main (&argc, &argv);
@@ -924,7 +932,7 @@ main (int argc, char **argv)
 
   atexit (close_stdout);
 
-  while ((optc = getopt_long (argc, argv, "b:c:d:f:nO:szw", longopts, NULL))
+  while ((optc = getopt_long (argc, argv, "b:c:d:f:F:nO:szw", longopts, NULL))
          != -1)
     {
       switch (optc)
@@ -937,8 +945,14 @@ main (int argc, char **argv)
             cut_mode = CUT_MODE_CHARACTERS;
           FALLTHROUGH;
         case 'f':
-          if (optc == 'f')
+        case 'F':
+          if (optc == 'f' || optc == 'F')
             cut_mode = CUT_MODE_FIELDS;
+          if (optc == 'F')
+            {
+              whitespace_delimited = true;
+              space_output_delimiter_default = true;
+            }
           if (spec_list_string)
             FATAL_ERROR (_("only one list may be specified"));
           spec_list_string = optarg;
@@ -977,6 +991,7 @@ main (int argc, char **argv)
 
         case 'w':
           whitespace_delimited = true;
+          whitespace_delimited_specified = true;
           trim_outer_whitespace
             = (optarg
                && XARGMATCH ("--whitespace-delimited", optarg,
@@ -1030,9 +1045,12 @@ main (int argc, char **argv)
 \tonly when operating on fields"));
     }
 
-  if (delim_specified && whitespace_delimited)
+  if (delim_specified && whitespace_delimited_specified)
     FATAL_ERROR (_("-d and -w are mutually exclusive"));
 
+  if (delim_specified && !whitespace_delimited_specified)
+    whitespace_delimited = false;
+
   set_fields (spec_list_string,
               (((cut_mode == CUT_MODE_BYTES
                  || cut_mode == CUT_MODE_CHARACTERS)
@@ -1049,9 +1067,17 @@ main (int argc, char **argv)
 
   if (output_delimiter_string == NULL)
     {
-      memcpy (output_delimiter_default, delim_bytes, delim_length);
       output_delimiter_string = output_delimiter_default;
-      output_delimiter_length = delim_length;
+      if (space_output_delimiter_default)
+        {
+          output_delimiter_default[0] = ' ';
+          output_delimiter_length = 1;
+        }
+      else
+        {
+          memcpy (output_delimiter_default, delim_bytes, delim_length);
+          output_delimiter_length = delim_length;
+        }
     }
 
   void (*cut_stream) (FILE *) = NULL;
index 6ce8bc46ee829827637fa72531b5b38f94a1de0a..f550f8f30700329aa91114d9c7569471d0854110 100755 (executable)
@@ -142,6 +142,9 @@ my @Tests =
   ['w-delim-6', '-w', '-f1,2', {IN=>"a  \n"}, {OUT=>"a\t\n"}],
   ['w-delim-7', '--whitespace-delimited', '-f1,2',
    {IN=>"  a b\n"}, {OUT=>"\ta\n"}],
+  ['F-delim-1', '-F', '2,3', {IN=>"a\tb  c\n"}, {OUT=>"b c\n"}],
+  ['F-delim-2', qw(-F 2,3 -O _), {IN=>"a\tb  c\n"}, {OUT=>"b_c\n"}],
+  ['F-delim-3', qw(-F 2,3 -d ,), {IN=>"1,2,3\n"}, {OUT=>"2 3\n"}],
   ['w-trim-1', '--whitespace-delimited=trimmed', '-f1,2',
    {IN=>"  a b  \n"}, {OUT=>"a\tb\n"}],
   ['w-trim-2', '-s', '--whitespace-delimited=trimmed', '-f1',