2
\$\begingroup\$

I'm looking for a better way of doing this code I made. I work for tech support and one of the biggest questions I am asked is: "Hey, how did my disk get so full in my VPS?"

I am aiming for output like:

home/ is taking up xGB
home/user1 xgb
home/user2 xgb

and so on. So far I have this, which does alright, but I am looking for a prettier way of getting this done.

#!/bin/bash
for i in $(ls -d */ |  grep -v proc);
 do
printf "**** $i has the following breakdown ********\n"

du -h --max-depth=1 $i
done
\$\endgroup\$
  • 1
    \$\begingroup\$ Even after you narrow it down to a specific user, you would still need to investigate that home directory. Have you used ncdu? \$\endgroup\$ – 200_success Jul 24 '18 at 23:49
  • \$\begingroup\$ yeeeee ncdu is alright... but doesn't script in too well... It's fine for me, being on my end, but I am trying to break it down dummy style for a customer that literally doesn't want to do anything. lol so my goal is to get the breakdown to look pretty and send it to the customer in a pretty pink bow \$\endgroup\$ – Charles Wilson Jul 25 '18 at 0:16
5
\$\begingroup\$

Use 'shellcheck' to spot common problems

200236.sh:2:12: warning: Don't use ls | grep. Use a glob or a for loop with a condition to allow non-alphanumeric filenames. [SC2010]
200236.sh:2:18: note: Use ./*glob* or -- *glob* so names with dashes won't become options. [SC2035]
200236.sh:4:8: note: Don't use variables in the printf format string. Use printf "..%s.." "$foo". [SC2059]
200236.sh:4:53: note: Backslash is literal in "\n". Prefer explicit escaping: "\\n". [SC1117]
200236.sh:6:21: note: Double quote to prevent globbing and word splitting. [SC2086]

Don't parse the output of ls

The ls program works well for interactive use, but isn't designed to be parsed by scripts. The main problem is that whitespace and other shell-significant characters are shown as-is, with no quoting. You could try to work around this using ls -b, but it's more robust to avoid the problem altogether:

for i in */
do
  if [[ i =~ proc ]]; then continue; fi
  # ...
done

The test for virtual filesystems is too broad

grep proc will pick up names such as processor - do you really want to exclude them? If you want to avoid inspecting filesystems not backed by disks, there are more reliable means:

case $(stat --file-system --format '%T' "$i") in
  proc|tmpfs|sysfs) continue ;;
esac

Always quote parameter expansions

du -h --max-depth=1 "$i"
#                   ^^^^

Don't expand parameters into a format string

Use echo or printf, but don't confuse the two ($i may contain %):

echo "**** $i has the following breakdown ********"
printf '**** %s has the following breakdown ********\n' "$i"

Constrain du to a single filesystem

I'm not sure whether or not you want du to cross mountpoints. If not, then add -x / --one-file-system to its options.


Modified code

#!/bin/bash
for i in */
do
    case $(stat --file-system --format '%T' "$i") in
        proc|tmpfs|sysfs) continue ;;
    esac

    echo "**** $i has the following breakdown ********"
    du -h --one-file-system --max-depth=1 "$i"
done
\$\endgroup\$
  • \$\begingroup\$ WOAH!!!!! Implementing testing and thank you so much! @toby This wasn't just an answer it was knowledge and I appreciate it. ALOT \$\endgroup\$ – Charles Wilson Jul 26 '18 at 3:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.