Hi, On 9/15/2014 10:58 PM, William Orr wrote:
> This diff adds a flag to du(1) to limit the depth of results > that are displayed to the user. > > The semantics are equivalent to FreeBSD's, where it is mutually > exclusive with -a and -s, and du -d 0 is equivalent to du -s. > > Thoughts? I think it's a bad idea and i'd prefer to not have this flag. It complicates the manual and code for almost no gain. Unix tools are supposed to do one thing each, and do it well. Selecting files out of a file hierarchy and providing options for selection is the task of find(1), not du(1). Doing what you want is trivial combining find and -exec du, or find | xargs du. What next? du --flags --group --name --user? However: * FreeBSD has it since 1996 (John-Mark Gurney is to blame for the bloat) * GNU coreutils has --max-depth since 1997 (Jim Meyering is to blame) * consequently, DragonFly has it forever (since 2003) * NetBSD has it since 2006 (Elad Efrat committed) * GNU coreutils has -d as an alias for --max-depth it since 2010 * illumos (and OpenSolaris before it) has different semantics: illumos du -d is the same as BSD du -x That may be a Sun invention, i have no idea. * Neither SysV nor 4.4BSD had a -d option. * POSIX does not have it. Even though it is not standardized, it seems so widespread by now that i think we better follow, given that it's not actively harmful and the bloat is relatively little: In my version of the patch, the actual prtout() tests become *simpler* instead of more complicated. I polished the diff in the following ways: * The meaning of the depth argument is much easier to understand when we explicitly say that -d 0 is the same as -s. * "Grand total" is used in two different senses; downgrade the smaller one to just "total" to reduce potential for confusion. * Mention that -d is a POSIX extension. * Correct HISTORY: du is v1, not v3; and add missing history of options. We are adding a new option, so it's a good time to do that. HISTORY can be checked here: http://mdocml.bsd.lv/cgi-bin/man.cgi/history/man1/du.1 * Simplify option handling: Delete two *flag variables instead of adding one. * Do not mix declarations and initialization. * Sort options in getopt(3). * Detect option clashes right away. That's better because it also catches duplicate -d options. * No need to cast the strtonum(3) return value. * Avoid duplicate "invalid" in error message. * Avoid a few excessively long lines. OK? Ingo P.S. William, whitespace was mangled in your patch. Index: du.1 =================================================================== RCS file: /cvs/src/usr.bin/du/du.1,v retrieving revision 1.31 diff -u -p -r1.31 du.1 --- du.1 14 Feb 2014 18:17:50 -0000 1.31 +++ du.1 16 Sep 2014 22:11:24 -0000 @@ -38,7 +38,7 @@ .Nd display disk usage statistics .Sh SYNOPSIS .Nm du -.Op Fl a | s +.Op Fl a | s | d Ar depth .Op Fl chkrx .Op Fl H | L | P .Op Ar @@ -61,6 +61,13 @@ The options are as follows: Display an entry for each file in the file hierarchy. .It Fl c Display the grand total after all the arguments have been processed. +.It Fl d Ar depth +Display an entry for each file and directory up to +.Ar depth +levels deep; +.Fl d Cm 0 +has the same effect as +.Fl s . .It Fl H Symbolic links on the command line are followed. Symbolic links encountered in the tree traversal are not followed. @@ -83,7 +90,7 @@ Generate messages about directories that that cannot be opened, and so on. This is the default. .It Fl s -Display only the grand total for the specified files. +Display only the total for each of the specified files and directories. .It Fl x File system mount points are not traversed. .El @@ -145,7 +152,7 @@ utility is compliant with the specification. .Pp The flags -.Op Fl chP , +.Op Fl cdhP , as well as the .Ev BLOCKSIZE environment variable, @@ -158,10 +165,55 @@ the obsolete .St -xcu5 standard. .Sh HISTORY -A +The .Nm -command first appeared in -.At v3 . +utility and its +.Fl a +and +.Fl s +options first appeared in +.At v1 . +.Pp +The +.Fl r +option first appeared in +.At III +and is available since +.Ox 2.3 . +The +.Fl k +and +.Fl x +options first appeared in +.Bx 4.3 Reno +and +.Fl H +in +.Bx 4.4 . +The +.Fl c +and +.Fl L +options first appeared in the GNU fileutils; +.Fl L +and +.Fl P +are available since +.Bx 4.4 Lite1 , +.Fl c +since +.Ox 2.1 . +The +.Fl d +option first appeared in +.Fx 2.2 +and is available since +.Ox 5.7 , +.Fl h +first appeared in +.Fx 4.0 +and is available since +.Ox 2.9 . .Sh AUTHORS .An -nosplit This version of Index: du.c =================================================================== RCS file: /cvs/src/usr.bin/du/du.c,v retrieving revision 1.25 diff -u -p -r1.25 du.c --- du.c 20 May 2014 01:25:23 -0000 1.25 +++ du.c 16 Sep 2014 22:11:24 -0000 @@ -40,6 +40,7 @@ #include <err.h> #include <errno.h> #include <fts.h> +#include <limits.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -59,16 +60,18 @@ main(int argc, char *argv[]) FTSENT *p; long blocksize; quad_t totalblocks; - int ftsoptions, listdirs, listfiles; - int Hflag, Lflag, aflag, cflag, hflag, kflag, sflag; + int ftsoptions, listfiles, maxdepth; + int Hflag, Lflag, cflag, hflag, kflag; int ch, notused, rval; char **save; + const char *errstr; save = argv; - Hflag = Lflag = aflag = cflag = hflag = kflag = sflag = 0; + Hflag = Lflag = cflag = hflag = kflag = listfiles = 0; totalblocks = 0; ftsoptions = FTS_PHYSICAL; - while ((ch = getopt(argc, argv, "HLPachksxr")) != -1) + maxdepth = -1; + while ((ch = getopt(argc, argv, "HLPacd:hkrsx")) != -1) switch (ch) { case 'H': Hflag = 1; @@ -82,7 +85,9 @@ main(int argc, char *argv[]) Hflag = Lflag = 0; break; case 'a': - aflag = 1; + if (maxdepth >= 0) + usage(); + listfiles = 1; break; case 'c': cflag = 1; @@ -96,13 +101,25 @@ main(int argc, char *argv[]) hflag = 0; break; case 's': - sflag = 1; + if (listfiles || maxdepth > 0) + usage(); + maxdepth = 0; break; case 'r': break; case 'x': ftsoptions |= FTS_XDEV; break; + case 'd': + if (listfiles || maxdepth >= 0) + usage(); + listfiles = 1; + maxdepth = strtonum(optarg, 0, INT_MAX, &errstr); + if (errstr) { + warnx("max depth %s: %s", optarg, errstr); + usage(); + } + break; case '?': default: usage(); @@ -129,16 +146,8 @@ main(int argc, char *argv[]) ftsoptions |= FTS_LOGICAL; } - if (aflag) { - if (sflag) - usage(); - listdirs = listfiles = 1; - } else if (sflag) - listdirs = listfiles = 0; - else { - listfiles = 0; - listdirs = 1; - } + if (maxdepth == -1) + maxdepth = INT_MAX; if (!*argv) { argv = save; @@ -171,12 +180,10 @@ main(int argc, char *argv[]) * or directories and this is post-order of the * root of a traversal, display the total. */ - if (listdirs || - (!listfiles && p->fts_level == FTS_ROOTLEVEL)) { + if (p->fts_level <= maxdepth) prtout((quad_t)howmany(p->fts_number, (unsigned long)blocksize), p->fts_path, hflag); - } break; case FTS_DC: /* Ignore. */ break; @@ -193,7 +200,7 @@ main(int argc, char *argv[]) * If listing each file, or a non-directory file was * the root of a traversal, display the total. */ - if (listfiles || p->fts_level == FTS_ROOTLEVEL) + if (listfiles && p->fts_level <= maxdepth) prtout(howmany(p->fts_statp->st_blocks, blocksize), p->fts_path, hflag); p->fts_parent->fts_number += p->fts_statp->st_blocks; @@ -315,6 +322,7 @@ usage(void) { (void)fprintf(stderr, - "usage: du [-a | -s] [-chkrx] [-H | -L | -P] [file ...]\n"); + "usage: du [-a | -s | -d depth] [-chkrx] [-H | -L | -P]" + " [file ...]\n"); exit(1); }