| 1 | #!/usr/bin/env bash |
| 2 | # Desc: Lists directories immediately containing large amounts of data |
| 3 | # Usage: script.sh [int megabytes] [dir] |
| 4 | # Example: A directory named `vacation_photos` located somewhere in $HOME/ |
| 5 | # containing more than 100MB of files (without checking subdirectories of |
| 6 | # `vacation_photos`) could be found by running: |
| 7 | # $ script.sh 100 "$HOME" |
| 8 | # /home/johndoe/Pictures/unsorted/notjunk/vacation_photos |
| 9 | # Version: 0.1.0 |
| 10 | |
| 11 | yell() { echo "$0: $*" >&2; } # print script path and all args to stderr |
| 12 | die() { yell "$*"; exit 111; } # same as yell() but non-zero exit status |
| 13 | must() { "$@" || die "cannot $*"; } # runs args as command, reports args if command fails |
| 14 | checkInt() { |
| 15 | # Desc: Checks if arg is integer |
| 16 | # Usage: checkInt arg |
| 17 | # Input: arg: integer |
| 18 | # Output: - return code 0 (if arg is integer) |
| 19 | # - return code 1 (if arg is not integer) |
| 20 | # Example: if ! checkInt $arg; then echo "not int"; fi; |
| 21 | # Version: 0.0.1 |
| 22 | local returnState |
| 23 | |
| 24 | #===Process Arg=== |
| 25 | if [[ $# -ne 1 ]]; then |
| 26 | die "ERROR:Invalid number of arguments:$#"; |
| 27 | fi; |
| 28 | |
| 29 | RETEST1='^[0-9]+$'; # Regular Expression to test |
| 30 | if [[ ! $1 =~ $RETEST1 ]] ; then |
| 31 | returnState="false"; |
| 32 | else |
| 33 | returnState="true"; |
| 34 | fi; |
| 35 | |
| 36 | #===Determine function return code=== |
| 37 | if [ "$returnState" = "true" ]; then |
| 38 | return 0; |
| 39 | else |
| 40 | return 1; |
| 41 | fi; |
| 42 | } # Checks if arg is integer |
| 43 | check_depends() { |
| 44 | local flag_return=0; |
| 45 | |
| 46 | if ! command -v du 1>/dev/random 2>&1; then flag_return=1; fi; |
| 47 | |
| 48 | return "$flag_return"; |
| 49 | }; # returns 1 if missing dependencies |
| 50 | size_dir_contents() { |
| 51 | # usage: size_dir_contents [path] |
| 52 | # depends: find, du |
| 53 | local bytes re; |
| 54 | |
| 55 | bytes=0; |
| 56 | re="^[0-9]+$"; |
| 57 | |
| 58 | #yell "DEBUG:Checking dir:$1"; |
| 59 | while read -r addend; do |
| 60 | #yell "DEBUG:addend:$addend"; |
| 61 | if [[ $addend =~ $re ]]; then |
| 62 | bytes="$((bytes + addend))"; |
| 63 | fi; |
| 64 | done < <( find "$1" -maxdepth 1 -type f -exec du -b --summarize '{}' \; | cut -f1 ); |
| 65 | |
| 66 | echo "$bytes" && return 0; |
| 67 | }; # return size of dir immediate contents |
| 68 | main() { |
| 69 | #size_large="100000000"; # 100 MB |
| 70 | |
| 71 | #yell "DEBUG:arg1:$1"; # debug |
| 72 | #yell "DEBUG:arg2:$2"; # debug |
| 73 | |
| 74 | # check dependencies |
| 75 | if ! check_depends; then die "FATAL:Missing dependencies."; fi; |
| 76 | |
| 77 | # check args |
| 78 | if ! checkInt "$1"; then |
| 79 | die "FATAL:Not an int:$1"; |
| 80 | else |
| 81 | size_l_mb="$1" |
| 82 | size_l_b="$(( size_l_mb * 1000000 ))"; |
| 83 | fi; |
| 84 | if [[ ! -d "$2" ]]; then |
| 85 | die "FATAL:Not a dir:$2"; |
| 86 | else |
| 87 | dir_in="$2"; |
| 88 | fi; |
| 89 | |
| 90 | # check each dir size contents |
| 91 | while IFS= read -r -d $'\0' pathdir; do |
| 92 | #yell "DEBUG:Checking:pathdir:$pathdir"; # debug |
| 93 | if [[ ! -d "$pathdir" ]]; then continue; fi; |
| 94 | dir_size="$(size_dir_contents "$pathdir";)" |
| 95 | #yell "DEBUG:dir_size:$dir_size"; # debug |
| 96 | if [[ $dir_size -gt "$size_l_b" ]]; then |
| 97 | printf "%s\n" "$pathdir"; # output |
| 98 | fi; |
| 99 | #sleep 1; # debug |
| 100 | done < <(find "$dir_in" -type d -print0); |
| 101 | |
| 102 | return 0; |
| 103 | }; |
| 104 | |
| 105 | main "$@"; |