• tree with dir size

    From Northwind@21:1/5 to All on Fri May 31 00:30:01 2024
    Hello,

    is there a command that shows dir/subdir structure like `tree`, but for
    each dir has the size in results as well?

    Thanks.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Greg Wooledge@21:1/5 to eben@gmx.us on Fri May 31 01:00:01 2024
    On Thu, May 30, 2024 at 06:51:30PM -0400, eben@gmx.us wrote:
    It looks like "tree --du" should do it, but "tree -d --du -h" says

    ├── [452K] Documents

    when du says it's 787M.

    Well, that sounds like one of the numbers includes subdirectories and
    the other only includes files in the immediate directory.

    The question is: which one do you want?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From eben@gmx.us@21:1/5 to Northwind on Fri May 31 01:00:01 2024
    On 5/30/24 18:28, Northwind wrote:
    Hello,

    is there a command that shows dir/subdir structure like `tree`, but for each dir has the size in results as well?

    It looks like "tree --du" should do it, but "tree -d --du -h" says

    ├── [452K] Documents

    when du says it's 787M.

    --
    When we've nuked the world to a cinder, the cockroaches picking
    over the remains will be crawling over the remaining artifacts
    and wondering what "PC LOAD LETTER" means. -- PC / ASR

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Northwind@21:1/5 to All on Fri May 31 01:00:01 2024
    both the size of current path and subdir should be expected.

    thanks.

    The question is: which one do you want?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Greg Wooledge@21:1/5 to Northwind on Fri May 31 01:10:01 2024
    On Fri, May 31, 2024 at 06:57:27AM +0800, Northwind wrote:
    both the size of current path and subdir should be expected.

    According to the man page, that's what it does.

    I just installed tree and tried it. There's a subtle behavior that I
    did not expect:

    hobbit:/usr/local$ tree -d --du -h
    [3.9M] .
    ├── [4.0K] bin
    ├── [4.0K] etc

    Those number are definitely not totals for the files in a directory.
    Compare:

    hobbit:/usr/local$ tree --du -h | less
    [627M] .
    ├── [ 81M] bin
    │   ├── [7.6K] addcr

    It looks like the -d option makes it only look at the size of the raw
    directory (4096 bytes, as in

    hobbit:/usr/local$ ls -ld bin
    drwxr-sr-x 2 root staff 4096 Feb 17 15:14 bin/

    ) rather than the total of the files within the directory.

    Solution: don't use -d. But then you get all the files listed instead
    of just the directories.

    If there's a way to get the pruning of files of -d plus the total-printing
    of omitting -d then I don't know what it is.

    The best workaround I can immediately see is to include -F to put trailing slashes on the directories, and then grep for those.

    hobbit:/usr/local$ tree --du -h -F | grep /$ | head
    [627M] ./
    ├── [ 81M] bin/
    ├── [4.0K] etc/
    ├── [4.0K] games/
    ├── [126K] include/
    │   └── [122K] opus/
    ├── [ 42M] lib/
    │   ├── [3.4M] nethackdir/
    │   │   ├── [4.0K] save/
    │   ├── [4.3K] pkgconfig/

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From eben@gmx.us@21:1/5 to Greg Wooledge on Fri May 31 02:10:01 2024
    On 5/30/24 18:54, Greg Wooledge wrote:
    On Thu, May 30, 2024 at 06:51:30PM -0400, eben@gmx.us wrote:
    It looks like "tree --du" should do it, but "tree -d --du -h" says

    ├── [452K] Documents

    when du says it's 787M.

    Well, that sounds like one of the numbers includes subdirectories and
    the other only includes files in the immediate directory.

    From du(1):

    --du For each directory report its size as the accumulation of
    sizes of all its files and sub-directories (and their files,
    and so on). The total amount of used space is also given in
    the final report (like the 'du -c' command.) This option
    requires tree to read the entire directory tree before
    emitting it, see BUGS AND NOTES below. Implies -s.

    OK, now for "du -c". From du(1):

    -c, --total
    produce a grand total

    Well, that doesn't help much.

    The question is: which one do you want?

    I'd like the size of the entire tree, and I think that's what OP wants too.

    I think "du -h -S -s Documents/" gives just the files in Documents, and not
    its subdirectories, and it gives 269M. "ls -ldh Documents/" says the
    directory itsely takes up 36k, so I'm not sure where "tree" got that number.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Greg Wooledge@21:1/5 to eben@gmx.us on Fri May 31 02:20:01 2024
    On Thu, May 30, 2024 at 08:04:26PM -0400, eben@gmx.us wrote:
    It looks like "tree --du" should do it, but "tree -d --du -h" says ├── [452K] Documents
    I think "du -h -S -s Documents/" gives just the files in Documents, and not its subdirectories, and it gives 269M. "ls -ldh Documents/" says the directory itsely takes up 36k, so I'm not sure where "tree" got that number.

    Hmm. Guessing again, it might be the sum of all the "-d" raw directory
    sizes of the directory and its subdirectories, but still ignoring files?
    I can't fathom why the programmer(s) decided to do this, because it
    isn't useful to anybody, but it's the only answer I can come up with.

    hobbit:~$ mkdir -p /tmp/x/y
    hobbit:~$ tree --du -dh /tmp/x
    [8.0K] /tmp/x
    └── [4.0K] y

    hobbit:~$ cp /vmlinuz /tmp/x
    hobbit:~$ tree --du -dh /tmp/x
    [8.0K] /tmp/x
    └── [4.0K] y

    Confusing and useless. I still don't have a better answer than this:

    hobbit:~$ tree --du -Fh /tmp/x | grep /$
    [7.8M] /tmp/x/
    └── [4.0K] y/

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Felix Miata@21:1/5 to All on Fri May 31 03:30:01 2024
    Northwind composed on 2024-05-31 06:28 (UTC+0800):

    is there a command that shows dir/subdir structure like `tree`, but for
    each dir has the size in results as well?

    Is ncdu any use to your need?
    --
    Evolution as taught in public schools is, like religion,
    based on faith, not based on science.

    Team OS/2 ** Reg. Linux User #211409 ** a11y rocks!

    Felix Miata

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Greg Wooledge@21:1/5 to Franco Martelli on Fri May 31 22:10:01 2024
    On Fri, May 31, 2024 at 09:18:03PM +0200, Franco Martelli wrote:
    On 31/05/24 at 02:18, Greg Wooledge wrote:
    Confusing and useless. I still don't have a better answer than this:

    hobbit:~$ tree --du -Fh /tmp/x | grep /$
    [7.8M]/tmp/x/
    └── [4.0K] y/

    It could be improved adding the "-a" switch to show also the hidden directories and the "--color" switch to the "grep" command but this sadly doesn't show the expected result (colorized directories) I don't know why:

    ~$ tree --du -Fah /tmp/x | grep --color /$

    You're only coloring the trailing / characters. If you want everything
    from after the last space to the end of the line, you'd want:

    tree --du -Fh /usr/local | grep --color '[^[:space:]]*/$'

    Of course this fails to colorize the entire directory name if there's
    a space in it.

    Me too needed to summarize the directory's size thus I wrote a bash function to accomplish this and added it to my /etc/profile.d/local.sh file:

    duhs() { IFS=$'\n\r' ; for d in $(/usr/bin/find $1 -maxdepth 1 -type d |/usr/bin/sort) ; do du -hs $d ; done }

    This, too, will fail if there are spaces in a directory name. You'd need
    to quote the "$1" and "$d" at the very least. The for d in $(find) part
    is also quite fragile; I see you tried to work around that by using IFS,
    but that's not a full fix. Also, you never declared IFS as a local
    variable in this function, so you will be altering IFS in any shell that actually runs this function.

    Consider this one instead:

    hobbit:~$ duhs() { du -hs "${1:-.}"/*/; }
    hobbit:~$ duhs /usr/local
    81M /usr/local/bin/
    4.0K /usr/local/etc/
    4.0K /usr/local/games/
    136K /usr/local/include/
    45M /usr/local/lib/
    29M /usr/local/man/
    8.0K /usr/local/sbin/
    2.2M /usr/local/share/
    484M /usr/local/src/
    44M /usr/local/tcl8.6/

    In bash, a glob that ends with / will match directories only. Globs are
    always sorted, so you can also drop the call to sort. The only issue
    with this version is if the number of subdirectories is so large that
    it triggers the "Argument list too long" error.

    If you want to avoid that, you can use xargs -0:

    duhs() { printf '%s\0' "${1:-.}"/*/ | xargs -0 du -sh; }

    As printf is a bash builtin, it can handle an unlimited number of
    arguments. So this form should work in all cases.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Wright@21:1/5 to Greg Wooledge on Sat Jun 1 04:40:01 2024
    On Fri 31 May 2024 at 16:03:22 (-0400), Greg Wooledge wrote:
    On Fri, May 31, 2024 at 09:18:03PM +0200, Franco Martelli wrote:
    On 31/05/24 at 02:18, Greg Wooledge wrote:
    Confusing and useless. I still don't have a better answer than this:

    hobbit:~$ tree --du -Fh /tmp/x | grep /$
    [7.8M]/tmp/x/
    └── [4.0K] y/

    It could be improved adding the "-a" switch to show also the hidden directories and the "--color" switch to the "grep" command but this sadly doesn't show the expected result (colorized directories) I don't know why:

    ~$ tree --du -Fah /tmp/x | grep --color /$

    You're only coloring the trailing / characters. If you want everything
    from after the last space to the end of the line, you'd want:

    tree --du -Fh /usr/local | grep --color '[^[:space:]]*/$'

    Of course this fails to colorize the entire directory name if there's
    a space in it.

    If a coloured ] is unimportant, I suppose you could use:

    tree --du -Fh whatever | grep --color '][[:space:]][[:space:]].*/$'

    Cheers,
    David.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Greg Wooledge@21:1/5 to David Wright on Sat Jun 1 05:20:01 2024
    On Fri, May 31, 2024 at 09:35:59PM -0500, David Wright wrote:
    If a coloured ] is unimportant, I suppose you could use:

    tree --du -Fh whatever | grep --color '][[:space:]][[:space:]].*/$'

    You don't need to count spaces. Just '].*/$' would suffice. We already
    know we want to start with the first ] character on the line, no matter
    how many spaces follow it.

    I really question the usefulness of colorizing the directory names,
    but since we're already this far down the rabbit hole, we might as
    well light some dynamite to make the hole deeper. I'm sure it's safe!

    We're using GNU grep for coloring, so we can also use its PCRE syntax
    to do "lookbehind" voodoo:

    tree --du -Fh /usr/local | grep --color -P '(?<=]).*/$'

    which means "start matching after a ] but don't include the ] in the
    match".

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From tomas@tuxteam.de@21:1/5 to Franco Martelli on Mon Jun 3 16:40:01 2024
    On Mon, Jun 03, 2024 at 03:52:54PM +0200, Franco Martelli wrote:

    ~$ tree --du -Fah /tmp/x | grep --color /$
    You're only coloring the trailing / characters. If you want everything from after the last space to the end of the line, you'd want:

    tree --du -Fh /usr/local | grep --color '[^[:space:]]*/$'

    I realized why "tree" command doesn't colorized the directories: "tree" detects that its std output goes through a pipe and therefore it disables
    the escaped code to colorize (like also "dmesg" does).

    That's what the "-C" option to tree is for.

    Cheers
    --
    "if everything else fails, read the man page"
    tomas

    -----BEGIN PGP SIGNATURE-----

    iF0EABECAB0WIQRp53liolZD6iXhAoIFyCz1etHaRgUCZl3T2wAKCRAFyCz1etHa RgfZAJ0em848NqvZIATj6fJvvytuuN8omQCeOazGmePOWcubCPvYaO0KoHotOBs=
    =SbWP
    -----END PGP SIGNATURE-----

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Andy Smith@21:1/5 to Franco Martelli on Mon Jun 3 16:40:01 2024
    Hi,

    On Mon, Jun 03, 2024 at 03:52:54PM +0200, Franco Martelli wrote:
    "tree" detects that its std output goes through a pipe and
    therefore it disables the escaped code to colorize (like also
    "dmesg" does). To avoid this behavior you must use the "unbuffer"
    command:

    unbuffer tree --du -Fah /usr/local | grep /$

    If that's the only thing you're using unbuffer for, why not just use
    the -C option of tree? It's a bit like the "--color=always" of ls.

    You can also try:

    ~# unbuffer dmesg | grep snd

    Similarly dmesg has "--color=always".

    I guess one advantage of unbuffer for this purpose is that you don't
    need for an option to exist or to know what it is if it does.

    Thanks,
    Andy

    --
    https://bitfolk.com/ -- No-nonsense VPS hosting

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Greg Wooledge@21:1/5 to Franco Martelli on Mon Jun 3 16:40:01 2024
    On Mon, Jun 03, 2024 at 03:52:54PM +0200, Franco Martelli wrote:
    On 31/05/24 at 22:03, Greg Wooledge wrote:
    It could be improved adding the "-a" switch to show also the hidden directories and the "--color" switch to the "grep" command but this sadly doesn't show the expected result (colorized directories) I don't know why:

    ~$ tree --du -Fah /tmp/x | grep --color /$
    You're only coloring the trailing / characters. If you want everything from after the last space to the end of the line, you'd want:

    tree --du -Fh /usr/local | grep --color '[^[:space:]]*/$'

    I realized why "tree" command doesn't colorized the directories: "tree" detects that its std output goes through a pipe and therefore it disables
    the escaped code to colorize (like also "dmesg" does).
    To avoid this behavior you must use the "unbuffer" command:

    unbuffer tree --du -Fah /usr/local | grep /$

    According to tree(1) there's a -C option which should force tree's
    coloring to be always on, even when stdout goes to a pipe. But tree
    never colors anything for me, even with -C and no pipe, so I don't know
    what else is needed.

    If you want to avoid that, you can use xargs -0:

    duhs() { printf '%s\0' "${1:-.}"/*/ | xargs -0 du -sh; }

    As printf is a bash builtin, it can handle an unlimited number of arguments. So this form should work in all cases.

    Thank you very much for revolutionizing my duhs() function, but sadly this version omits to show the hidden directories. Do you have a version that it shows also those directories? For me it's so hard to figure out what the "${1:-.}"/*/ block does.

    "$1" is the first argument given to the function. It can also be written
    as "${1}".

    "${1:-default}" is the first argument given to the function, *or* the
    constant string 'default' if the first argument is empty or not given. Therefore, "${1:-.}" is "the first argument, or default to . if no
    argument is given".

    Since that part is quoted, whatever value is used is taken as a string,
    with no word splitting or globbing applied. That means it will handle directory names that contain spaces, asterisks, etc.

    Given the glob "x"/*/ the shell will look for all the subdirectories
    of "x". The trailing / forces it to ignore anything that isn't a
    directory.

    You can see it in action:

    hobbit:~$ printf '%s\n' /usr/local/*/
    /usr/local/bin/
    /usr/local/etc/
    /usr/local/games/
    /usr/local/include/
    /usr/local/lib/
    /usr/local/man/
    /usr/local/sbin/
    /usr/local/share/
    /usr/local/src/
    /usr/local/tcl8.6/

    So, putting it all together, that glob says "all the subdirectories of
    the first argument, or all the subdirectories of . if there was no
    argument given".

    Getting it to include directory names that begin with . is trickier.
    The simplest way would be to turn on bash's dotglob option, and then
    turn it off again at the end:

    duhs() {
    shopt -s dotglob
    printf '%s\0' "${1:-.}"/*/ | xargs -0 du -sh
    shopt -u dotglob
    }

    But this assumes that the option was *not* already on when we entered
    the function. If it was on, we've just turned it off. Another way to
    do this, which doesn't permanently alter the option for the remainder
    of the shell's lifetime, would be to wrap the function body in a subshell:

    duhs() {
    (
    shopt -s dotglob
    printf '%s\0' "${1:-.}"/*/ | xargs -0 du -sh
    )
    }

    The formatting choices here are legion.

    There are a few other options, but they become increasingly arcane from
    here. The subshell is probably the most straightforward choice. The
    function is already forking child processes, so from a performance point
    of view, adding a subshell won't be much worse.

    I'll also throw in one last piece of information because if I don't,
    someone else is likely to do it, without a good explanation.
    Syntactically, the body of a shell function doesn't have to be enclosed
    in curly braces. The body can be any compound command, and a curly-brace command group is just one example of a compound command. A subshell is
    another example. So, it could also be written this way:

    duhs() (
    shopt -s dotglob
    printf '%s\0' "${1:-.}"/*/ | xargs -0 du -sh
    )

    I'm not personally fond of this. It's extremely easy to overlook
    the fact that the curly braces have been replaced with parentheses,
    especially in certain fonts. Nevertheless, some people like this.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From tomas@tuxteam.de@21:1/5 to Andy Smith on Mon Jun 3 19:10:01 2024
    On Mon, Jun 03, 2024 at 02:36:43PM +0000, Andy Smith wrote:

    [...]

    If that's the only thing you're using unbuffer for, why not just use
    the -C option of tree? It's a bit like the "--color=always" of ls.

    Oh, and the complementary option for `less', while we're at it, would
    be -R:

    tree -C | less -R

    (I tend to add -SX to less: people might like those or not).

    Cheers
    --
    t

    -----BEGIN PGP SIGNATURE-----

    iF0EABECAB0WIQRp53liolZD6iXhAoIFyCz1etHaRgUCZl32pgAKCRAFyCz1etHa RqUDAJwJ0Alue6Iy2mXkWPb0TO9dcT00fwCeJWvvwb0m0SQuVzMUvRaIdu4JYqQ=
    =Fzd+
    -----END PGP SIGNATURE-----

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Greg Wooledge@21:1/5 to David Wright on Mon Jun 3 21:10:01 2024
    On Mon, Jun 03, 2024 at 01:11:57PM -0500, David Wright wrote:
    On Mon 03 Jun 2024 at 10:32:16 (-0400), Greg Wooledge wrote:
    duhs() (
    shopt -s dotglob
    printf '%s\0' "${1:-.}"/*/ | xargs -0 du -sh
    )

    I'm not personally fond of this. It's extremely easy to overlook
    the fact that the curly braces have been replaced with parentheses,

    I guess minimalists would make a one-liner out of that.
    Myself, I prefer verbosity, and the ability to search and find
    all my functions with /function.*{$ in less. For example,
    I write what is probably my most trivial function in .bashrc as:

    function _Cat_ {
    cat
    }

    rather than:

    _Cat_() { cat; }

    ... I feel like you've just exemplified what I was talking about, missing
    the fact that the curly braces were replaced with parentheses around the function body to force a subshell every time it's called.

    It had nothing to do with how many lines of code were used. I could
    have written them as

    duhs() { (shopt -s dotglob; printf '%s\0' "${1:-.}"/*/ | xargs -0 du -sh); }

    and

    duhs() (shopt -s dotglob; printf '%s\0' "${1:-.}"/*/ | xargs -0 du -sh)

    and the same point would have applied.

    function _Cat_ {

    Do note that the "function" keyword is a bash/ksh extension, and not
    part of POSIX sh syntax. In bash, "x()" and "function x" are identical
    in behavior. In ksh, they cause two different kinds of variable scoping behavior. Bash also allows "function x()" which ksh does not.

    Just for the record.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Greg Wooledge@21:1/5 to Franco Martelli on Tue Jun 4 00:30:01 2024
    On Mon, Jun 03, 2024 at 10:45:28PM +0200, Franco Martelli wrote:
    On 03/06/24 at 16:32, Greg Wooledge wrote:
    duhs() {
    (
    shopt -s dotglob
    printf '%s\0' "${1:-.}"/*/ | xargs -0 du -sh
    )
    }

    I've some issue with this function. It doesn't show the size of the
    directory specified as argument, it follows the output of my original function:

    I started writing a response to this, because it seemed easy enough to
    fix -- just add "${1:-.}" to the printf arguments, so it gets passed
    along to du -sh, and included in the output.

    But then I tested it.

    hobbit:~$ du -sh /usr/local /usr/local/bin
    684M /usr/local

    What? Where's the second line?

    hobbit:~$ du -sh /usr/local/bin /usr/local/etc
    81M /usr/local/bin
    4.0K /usr/local/etc

    Multiple arguments are allowed....

    hobbit:~$ du -sh /usr/local/bin /usr/local/etc /usr/local
    81M /usr/local/bin
    4.0K /usr/local/etc
    603M /usr/local

    You're even allowed to have a parent directory after its children...

    hobbit:~$ du -sh /usr/local /usr/local/bin /usr/local/etc
    684M /usr/local

    ... but if the parent is FIRST, the children get... swallowed up by
    it? Huh? And if the parent is last, then the value shown for the
    parent excludes the children that were already reported on?

    Why the HELL is it like this?!

    It doesn't even match its own documentation. Here's what the info
    page says:

    ‘-s’
    ‘--summarize’
    Display only a total for each argument.

    There's supposed to be a total *FOR EACH ARGUMENT*. There isn't.

    OK, I officially wash my hands of ANY solution based on du -s. If
    you want to try to make it work sensibly, more power to you. As far
    as I'm concerned, though, this is broken. Irreparably broken.

    It looks like tree(1) is less broken, so it might be better to stick
    with that, even if you have to pipe the output through grep to get what
    you want.

    *Sigh*.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From David Wright@21:1/5 to Greg Wooledge on Tue Jun 4 02:40:01 2024
    On Mon 03 Jun 2024 at 15:03:37 (-0400), Greg Wooledge wrote:
    On Mon, Jun 03, 2024 at 01:11:57PM -0500, David Wright wrote:
    On Mon 03 Jun 2024 at 10:32:16 (-0400), Greg Wooledge wrote:
    duhs() (
    shopt -s dotglob
    printf '%s\0' "${1:-.}"/*/ | xargs -0 du -sh
    )

    I'm not personally fond of this. It's extremely easy to overlook
    the fact that the curly braces have been replaced with parentheses,

    I guess minimalists would make a one-liner out of that.
    Myself, I prefer verbosity, and the ability to search and find
    all my functions with /function.*{$ in less. For example,
    I write what is probably my most trivial function in .bashrc as:

    function _Cat_ {
    cat
    }

    rather than:

    _Cat_() { cat; }

    ... I feel like you've just exemplified what I was talking about, missing
    the fact that the curly braces were replaced with parentheses around the function body to force a subshell every time it's called.

    _Puss_() ( cat )

    if it makes you happy; but no, you made your point about parentheses
    perfectly well. It's just that _Cat_ doesn't require a subshell for
    /its/ purpose.

    It had nothing to do with how many lines of code were used. I could
    have written them as

    duhs() { (shopt -s dotglob; printf '%s\0' "${1:-.}"/*/ | xargs -0 du -sh); }

    and

    duhs() (shopt -s dotglob; printf '%s\0' "${1:-.}"/*/ | xargs -0 du -sh)

    and the same point would have applied.

    function _Cat_ {

    Do note that the "function" keyword is a bash/ksh extension, and not
    part of POSIX sh syntax. In bash, "x()" and "function x" are identical
    in behavior. In ksh, they cause two different kinds of variable scoping behavior. Bash also allows "function x()" which ksh does not.

    Just for the record.

    Noted. (Franco did mention using bash, and I mentioned .bashrc.)
    I'm a bit old for switching shells now!

    Cheers,
    David.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Greg Wooledge@21:1/5 to David Wright on Tue Jun 4 03:50:01 2024
    On Mon, Jun 03, 2024 at 07:42:17PM -0500, David Wright wrote:
    On Mon 03 Jun 2024 at 18:29:17 (-0400), Greg Wooledge wrote:
    ‘-s’
    ‘--summarize’
    Display only a total for each argument.

    There's supposed to be a total *FOR EACH ARGUMENT*. There isn't.

    Try adding -l. The idea is that du is trying to avoid double-counting,
    so when the subdirectories come first, those ones are "used up" by
    the time it reaches the parent. When the parent is first, it's (all)
    the subdirectories instead that have been "used up".

    ‘-l’
    ‘--count-links’
    Count the size of all files, even if they have appeared already (as
    a hard link).

    This documentation leaves a lot to be desired.

    Anyway, you are correct about the result, even if the documentation gives
    no realistic way to conclude such a result.

    hobbit:~$ printf '%s\0' "${1:-.}" "${1:-.}"/*/ | xargs -0 du -shl
    684M /usr/local
    81M /usr/local/bin/
    4.0K /usr/local/etc/
    4.0K /usr/local/games/
    136K /usr/local/include/
    45M /usr/local/lib/
    29M /usr/local/man/
    8.0K /usr/local/sbin/
    31M /usr/local/share/
    484M /usr/local/src/
    44M /usr/local/tcl8.6/

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Greg Wooledge@21:1/5 to Franco Martelli on Tue Jun 4 16:50:01 2024
    On Tue, Jun 04, 2024 at 04:40:07PM +0200, Franco Martelli wrote:
    FYI the revision of duhs() I adopt is:

    duhs() { ( shopt -s dotglob; printf '%s\0' "${1:-.}" "${1:-.}"*/ | xargs -0 du -shl ) } ↑

    Please note that I dropped a "/" in the "${1:-.}"/*/ block because the directories listed had a double "//" in their names:

    That's because you're passing directories with a trailing / from your
    shell. Probably because you're using tab completions.

    If you pass "/usr/local" as the argument instead of

    ~# duhs /usr/local/
    88K /usr/local/
    4,0K /usr/local//bin/
    4,0K /usr/local//etc/
    4,0K /usr/local//games/
    4,0K /usr/local//include/
    4,0K /usr/local//man/
    4,0K /usr/local//sbin/
    60K /usr/local//share/
    4,0K /usr/local//src/

    you will see that you've broken it now.

    If you really care about removing the double slashes from the case
    where you pass an extra trailing slash in your input, you should use
    parameter expansions or some other filtering to remove one of the
    slashes. That would be better than breaking your function.

    duhs() {
    (
    shopt -s dotglob
    s=${1:-.}
    s=${s%/}
    printf '%s\0' "${s:-.}" "${s:-.}"/*/ | xargs -0 du -shl
    )
    }

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)