How can I use find to select users with a certain amount of disk space usage?

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?

shantanuo

Posted 2011-05-16T06:34:14.293

Reputation: 2 119

I am looking for a solution that will work with "find" command. – shantanuo – 2011-05-19T12:03:49.003

5Any 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 – 2011-05-19T14:01:11.687

Can you please post this as an answer? This seems to working. But how do I get human readable disk consumption figure? – shantanuo – 2011-05-23T04:20:32.433

Answers

0

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.

Phil

Posted 2011-05-16T06:34:14.293

Reputation: 525

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.

Mat

Posted 2011-05-16T06:34:14.293

Reputation: 6 193

The first example worked as expected. In case of second command, the $size is treated as text and not as number. – shantanuo – 2011-05-17T11:28:35.453

@shantanuo: I don't understand that comment. There is only one script above. – Mat – 2011-05-19T16:50:41.520

@shantanuo What is your shell? Mat wrote that his answer is for bash. – Daniel Beck – 2011-05-20T17:12:18.287

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.

Heath

Posted 2011-05-16T06:34:14.293

Reputation: 705

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.

vtest

Posted 2011-05-16T06:34:14.293

Reputation: 4 424