Reputation: 1313
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
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
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
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