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.