6

I want to find all users shown in the /home/ directory whose disk consumption is more than 500MB. The following command works as expected.

cd /home/ && du */ -hs
68K     ajay/
902M    john/
250M    websites/

From the above example, only 902M john/ should be returned.

How can I make the find command output the same results?

3
  • I am looking for a solution that will work with "find" command.
    – shantanuo
    May 19, 2011 at 12:03
  • 5
    Any particular reason why do you want to use find for this task? I would just do cd /home/ && du */ -ms | awk '$1 > 500 { print $0 }'
    – vtest
    May 19, 2011 at 14:01
  • Can you please post this as an answer? This seems to working. But how do I get human readable disk consumption figure?
    – shantanuo
    May 23, 2011 at 4:20

4 Answers 4

0
+50

You can't do this only with find, because find acts on individual files, and doesn't have a concept of adding up file sizes. You could pipe the output of find into another tool, but why bother when du does most of the work?

du -sm */ | sort -k1,1n | awk '$1 > 500 { sub(/$/, "M", $1); print $0 }'

The awk test becomes messy when the "human-readable" suffix in included in the input, because you need to strip off the trailing "M" to do an integer comparison. For the output, personally I'd skip the "M" suffix, but that's what was requested.

4

Not sure why you want something like find, so here's a scriptlet that does what you ask in bash (but doesn't work like find):

max_size=$((500*1024))
cd /home/ && du -ks */ | while read size user ; do
  if [ $size -gt $max_size ] ; then
    echo "${user%/} exceeds quota"
  fi
done

Example: (with a smaller size):

$ du -sk */
2948    a/
4       a b/
640     b/
48      qt/

$ du -ks */ | while read size user ; do if [ $size -gt 600 ] ; then echo "${user%/} exceeds quota" ; fi ; done
a exceeds quota
b exceeds quota

The ${user%/} just removes the trailing slash for extra prettyness.

3
  • The first example worked as expected. In case of second command, the $size is treated as text and not as number.
    – shantanuo
    May 17, 2011 at 11:28
  • @shantanuo: I don't understand that comment. There is only one script above.
    – Mat
    May 19, 2011 at 16:50
  • @shantanuo What is your shell? Mat wrote that his answer is for bash.
    – Daniel Beck
    May 20, 2011 at 17:12
0

This will print the disk usage (in kb) for each user's files in dir regardless of where those files are:

find dir -printf "%u %b\n" | perl -n -e '@l = split; $sum{$l[0]} += $l[1]; END { foreach(sort(keys(%sum))) { print "$_ ",$sum{$_}/2," KiB\n"; }}'

The find command prints the owner and block count of each file and directory in dir. The perl command adds the usage into a hash keyed on the username, thus building a sum of each user's file sizes; and then the contents of the hash is printed out.

0

Posting as answer.

I have used du -ms to get consistent output that can be processed by awk without additional intervention. You are correct that human readable output is better, so the final output gets processed once again for that.

#!/bin/bash

######################################################################
#  AUTHOR: Joe Negron - LOGIC Wizards ~ NYC
#  LICENSE: BuyMe-a-Drinkware: Dual BSD or GPL (pick one)
#  USAGE: byteMe (bytes)
#  ABSTRACT: Converts a numeric parameter to a human readable format.
#  URL: http://www.logicwizards.net/2010/10/19/byteme-a-simple-binary-metrics-bash-script-howto-convert-bytes-into-kb-mb-gb-etc-using-bash-bc/
######################################################################
function byteMe() { # Divides by 2^10 until < 1024 and then append metric suffix
declare -a METRIC=('B' 'KB' 'MB' 'GB' 'TB' 'XB' 'PB') # Array of suffixes
MAGNITUDE=0  # magnitude of 2^10
PRECISION="scale=1" # change this numeric value to inrease decimal precision
UNITS=`echo $1 | tr -d ','`  # numeric arg val (in bytes) to be converted
while [ ${UNITS/.*} -ge 1024 ] # compares integers (b/c no floats in bash)
  do
   UNITS=`echo "$PRECISION; $UNITS/1024" | bc` # floating point math via `bc`
   ((MAGNITUDE++)) # increments counter for array pointer
  done
echo -n "$UNITS${METRIC[$MAGNITUDE]}"
}

cd /home/ && du */ -bs | awk '$1 > 500 { print $0 }' | while read LINE; do
    SIZE=$(echo "$LINE" | cut -f 1)
    HRSIZE=$(byteMe "$SIZE")
    DIR=$(echo "$LINE" | cut -f 2)
    printf "%8s %s\n" "$HRSIZE" "$DIR"
done

Notes:

  1. bash function was found by googling (see the comments)
  2. I have changed du -ms to du -bs, thus making it possible to use the conversion function that accepts bytes.
  3. The 500MB limit is still hardcoded. Feel free to modify the script to accept it as argument.

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.