I'm honored and pleased to be the person who gets to complete ls
. This
project, begun around when I was born, was slow to turn into anything more
than a simple for
loop over a dirent. It really took off in the mid and
late 80's, when Richard Stallman added numerous features, and the growth
has been steady ever since. But, a glance at the man page shows that
ls
has never quite been complete. It fell to me to finish the job, and
I have produced several handy patches to this end:
- http://bugs.debian.org/666198 adds -y (necessary for compatability with old shar archives)
- http://bugs.debian.org/666244 adds -e (entangled directory display option, quite nice)
- http://bugs.debian.org/666684 adds -j (suitable output format for twitter, cell phones, other 21st century media)
The only obvious lack now is a -z option, which should make output filenames be NULL terminated for consuption by other programs. I think this would be easy to write, but I've been extermely busy IRL (moving lots of furniture) and didn't get to it. Any takers to write it?
Due to the nature of these patches, they conflict with each other. Here's a combined patch suitable to be applied and tested.
diff -ur orig/coreutils-8.13/src/ls.c coreutils-8.13/src/ls.c --- orig/coreutils-8.13/src/ls.c 2011-07-28 06:38:27.000000000 -0400 +++ coreutils-8.13/src/ls.c 2012-04-01 12:41:56.835106346 -0400 @@ -270,6 +270,7 @@ static int format_group_width (gid_t g); static void print_long_format (const struct fileinfo *f); static void print_many_per_line (void); +static void print_jam (void); static size_t print_name_with_quoting (const struct fileinfo *f, bool symlink_target, struct obstack *stack, @@ -382,6 +383,7 @@ many_per_line for just names, many per line, sorted vertically. horizontal for just names, many per line, sorted horizontally. with_commas for just names, many per line, separated by commas. + jam to fit in the most information possible. -l (and other options that imply -l), -1, -C, -x and -m control this parameter. */ @@ -392,7 +394,8 @@ one_per_line, /* -1 */ many_per_line, /* -C */ horizontal, /* -x */ - with_commas /* -m */ + with_commas, /* -m */ + jam /* -j */ }; static enum format format; @@ -630,6 +633,11 @@ static bool immediate_dirs; +/* True means when multiple directories are being displayed, combine + * their contents as if all in one directory. -e */ + +static bool entangle_dirs; + /* True means that directories are grouped before files. */ static bool directories_first; @@ -705,6 +713,10 @@ static bool format_needs_type; +/* Answer "yes" to all prompts. */ + +static bool yes; + /* An arbitrary limit on the number of bytes in a printed time stamp. This is set to a relatively small value to avoid the need to worry about denial-of-service attacks on servers that run "ls" on behalf @@ -804,6 +816,7 @@ {"escape", no_argument, NULL, 'b'}, {"directory", no_argument, NULL, 'd'}, {"dired", no_argument, NULL, 'D'}, + {"entangle", no_argument, NULL, 'e'}, {"full-time", no_argument, NULL, FULL_TIME_OPTION}, {"group-directories-first", no_argument, NULL, GROUP_DIRECTORIES_FIRST_OPTION}, @@ -849,12 +862,12 @@ static char const *const format_args[] = { "verbose", "long", "commas", "horizontal", "across", - "vertical", "single-column", NULL + "vertical", "single-column", "jam", NULL }; static enum format const format_types[] = { long_format, long_format, with_commas, horizontal, horizontal, - many_per_line, one_per_line + many_per_line, one_per_line, jam }; ARGMATCH_VERIFY (format_args, format_types); @@ -1448,6 +1461,9 @@ print_dir_name = true; } + if (entangle_dirs) + print_current_files (); + if (print_with_color) { int j; @@ -1559,6 +1575,7 @@ print_block_size = false; indicator_style = none; print_inode = false; + yes = false; dereference = DEREF_UNDEFINED; recursive = false; immediate_dirs = false; @@ -1644,7 +1661,7 @@ { int oi = -1; int c = getopt_long (argc, argv, - "abcdfghiklmnopqrstuvw:xABCDFGHI:LNQRST:UXZ1", + "abcdefghijklmnopqrstuvw:xyABCDFGHI:LNQRST:UXZ1", long_options, &oi); if (c == -1) break; @@ -1667,6 +1684,10 @@ immediate_dirs = true; break; + case 'e': + entangle_dirs = true; + break; + case 'f': /* Same as enabling -a -U and disabling -l -s. */ ignore_mode = IGNORE_MINIMAL; @@ -1697,6 +1718,10 @@ print_inode = true; break; + case 'j': + format = jam; + break; + case 'k': human_output_opts = 0; file_output_block_size = output_block_size = 1024; @@ -1765,6 +1790,10 @@ format = horizontal; break; + case 'y': + yes = true; + break; + case 'A': if (ignore_mode == IGNORE_DEFAULT) ignore_mode = IGNORE_DOT_AND_DOTDOT; @@ -2510,7 +2539,7 @@ DEV_INO_PUSH (dir_stat.st_dev, dir_stat.st_ino); } - if (recursive || print_dir_name) + if ((recursive || print_dir_name) && ! entangle_dirs) { if (!first) DIRED_PUTCHAR ('\n'); @@ -2526,7 +2555,8 @@ /* Read the directory entries, and insert the subfiles into the `cwd_file' table. */ - clear_files (); + if (! entangle_dirs) + clear_files (); while (1) { @@ -2615,7 +2645,7 @@ DIRED_PUTCHAR ('\n'); } - if (cwd_n_used) + if (cwd_n_used && ! entangle_dirs) print_current_files (); } @@ -3464,6 +3494,10 @@ print_with_commas (); break; + case jam: + print_jam (); + break; + case long_format: for (i = 0; i < cwd_n_used; i++) { @@ -4418,6 +4452,24 @@ putchar ('\n'); } +static void +print_jam (void) +{ + size_t filesno; + size_t pos = 0; + + for (filesno = 0; filesno < cwd_n_used; filesno++) + { + struct fileinfo const *f = sorted_file[filesno]; + size_t len = length_of_file_name_and_frills (f); + + print_file_name_and_frills (f, pos); + pos += len; + } + putchar ('\n'); +} + + /* Assuming cursor is at position FROM, indent up to position TO. Use a TAB character instead of two or more spaces whenever possible. */ @@ -4627,11 +4679,13 @@ -D, --dired generate output designed for Emacs' dired mode\n\ "), stdout); fputs (_("\ + -e, --entangle display multiple directory contents as one\n\ -f do not sort, enable -aU, disable -ls --color\n\ -F, --classify append indicator (one of */=>@|) to entries\n\ --file-type likewise, except do not append `*'\n\ --format=WORD across -x, commas -m, horizontal -x, long -l,\n\ single-column -1, verbose -l, vertical -C\n\ + jam -j\n\ --full-time like -l --time-style=full-iso\n\ "), stdout); fputs (_("\ @@ -4667,6 +4721,8 @@ -i, --inode print the index number of each file\n\ -I, --ignore=PATTERN do not list implied entries matching shell PATTERN\ \n\ + -j jam output together, makes the most of limited\n\ + space on modern systems (cell phones, twitter)\n\ -k like --block-size=1K\n\ "), stdout); fputs (_("\ @@ -4733,6 +4789,7 @@ -w, --width=COLS assume screen width instead of current value\n\ -x list entries by lines instead of by columns\n\ -X sort alphabetically by entry extension\n\ + -y answer all questions with \"yes\"\n\ -Z, --context print any SELinux security context of each file\n\ -1 list one file per line\n\ "), stdout);
It remains to be seen if multi-option enabled coreutils will be accepted into Debian in time for the next release. Due to some disagreements with the coreutils maintainer, the matter has been referred to the Technical Committee (Flattr me)
Traditionally new ls
contributors stop once enough options have been
added that they can spell their name, in the best traditions of yellow
snow. Once ls -richard -stallman
worked, I'm sure RMS moved on other
other more pressing concerns. The current maintainer, David MacKenzie, was
clearly not done yet, since only ls -david -mack
worked. But he was being
slow to add these last few features, and ls
was very deficient in the realm
of spelling my name (ls -o -hss
.. srsly?), so I took matter into my own
hands in the best tradition of free software.
… and of course the option -z would be used to NUL-terminate lines, instead of using \n. Finally, an alphabetically complete ls command.