Josh
Josh

Reputation: 1313

Bash command to check available drive space (was "to check value of a decimal number")

I have this code, which checks that the remaining disk space on a specific drive and then runs a set of commands.

if [ "$(echo "$(df -h | awk '$1 == "drive_name" {print $4}' | sed 's/[T]//') >= 0.2" | bc)" -eq 1 ]; then 
    <run_these_commands>; 
else 
    <run_other_commands>; 
fi

It works, but the [] test is a mess. Is there a better way to do this?

Upvotes: 0

Views: 585

Answers (3)

Saboteur
Saboteur

Reputation: 1428

For simple command you can use:

[ $(df -m --output=avail /|tail -n1) -lt 200 ] && echo issue || echo not issue

or with if to make it more readable:

if [ $(df -m --output=avail /|tail -n1) -lt 200 ]; then
 commands
else
  commands
fi

-m means megabytes. You can use test command to compare (-lt means less then)

Upvotes: 0

L&#233;a Gris
L&#233;a Gris

Reputation: 19545

Do it all with proper df arguments:

declare -- drive='/'
declare -i minsize=$((2*10**11)) # 200 GB
if (($(df -B1 --output=avail "$drive" | tail -1)>=minsize))
then
   printf 'There is more than 200 GB left on %s\n' "$drive"
else
   printf 'There is less than 200 GB left on %s\n' "$drive"
fi

df:

  • -B1: Sets display block size to 1 byte, so it is always an integer.

  • --output=avail: Displays only available space field.

  • "$drive": Show only for device or mountpoint

| tail:

  • -1: Show only last line (skip header lines, so it returns only the integer byte amount of free space).

((…)): Bash allows stand-alone arithmetic, so use it in the if condition. Since only integer values are dealt with, it can be handled natively by the shell without need for bc.

Upvotes: 6

Benjamin W.
Benjamin W.

Reputation: 52102

As a list of iterative improvements, I'd suggest the following:

  • Instead of comparing the output of bc to 1, use the ((...)) conditional construct, which returns a successful exit status for 1, i.e., translates the output of bc directly. This allows us to drop the outermost command substitution and -eq 1:

    if (($(echo "$(df -h | awk '$1 == "drive_name" {print $4}' | sed 's/[T]//') >= 0.2" | bc))); then
    
  • Instead of echo "$(cmd) >= 0.2 | bc, we can use bc <<< "$cmd >= 0.2", which saves us a subshell and is a little shorter:

    if (($(bc <<< "$(df -h | awk '$1 == "drive_name" {print $4}' | sed 's/[T]//') >= 0.2"))); then
    
  • The T in the sed command doesn't need to go into square brackets, it's not special:

    if (($(bc <<< "$(df -h | awk '$1 == "drive_name" {print $4}' | sed 's/T//') >= 0.2"))); then
    
  • In fact, we don't need sed at all to remove the T:

    if (($(bc <<< "$(df -h | awk '$1 == "drive_name" {sub(/T/, "", $4); print $4}') >= 0.2"))); then
    
  • We also don't need bc, because awk can compare to 0.2 itself:

    if (($(df -h | awk '$1 == "drive_name" {sub(/T/, "", $4); print $4 >= 0.2}'))); then
    
  • We can get rid of the whole T business by not using the -h flag and comparing to kilobytes instead of terabytes:

    if (($(df | awk '$1 == "drive_name" {print $4 >= 0.2*1e9}'))); then
    

    (This is actually not exactly the same, as df -h uses multiples of 1024, but probably good enough.)

  • We can tell df to just tell us about the filesystem we're interested in, then we know for sure the information we want is on the second line of output:

    if (($(df drive_name | awk 'NR == 2 {print $4 >= 0.2*1e9}'))); then
    
  • We can have df give us just the available space:

    if (($(df --output=avail drive_name | awk 'NR == 2 {print $1 >= 0.2*1e9}'))); then
    
  • And finally, we can make the comparison in Bash directly, we just need something to delete the first line of df output:

    if (($(df --output=avail drive_name | sed '1d') >= 2*10**8)); then
    

    Notice that we've switched from 0.2e9 to 2 * 10**8 to get around using floating point.

Upvotes: 1

Related Questions