Script To Add A Swap File
A certain operation needed more as 20 GB of memory. Because my system only has 14 GB RAM and 9 GB swap that was a problem. I could have manually created a swapfile, but I thought maybe other people have sometimes the same problem. And I thought it a nice example of how to create a Bash script.
The main part is what you mostly would do yourself when creating and adding the swapfile manually:
echo date "+%T: Creating ${_swapFile}"
dd if=/dev/zero of=${_swapFile} bs=1024 count=$(($_gb * 1024 ** 2))
echo
chmod 600 ${_swapFile}
mkswap ${_swapFile}
swapon ${_swapFile}
I always prepend read only variables with a _. So variables that start with a _ are read only.
You could say it is a small script, so why bother, but I think it is 'always' a good idea to make variables that should not change read only.
When you need to calculate something in Bash you do this with $((expression)).
You use ** for exponential, so 1024 ** 2 gives a million.
Block count is a kilobyte, so I need a million blocks pro gigabyte.
That is why the calculation is done with $(($_gb * 1024 ** 2))
It would be nice to see the effect, so before this I have:
echo Current Swap:
swapon
and after I have:
echo New Swap:
swapon
We need to be sure the swapfile is not to big. I think that the swapfile should be less as a quarter of the free space on the partition it is created on:
declare -ir _gbFree=$(getFreeGB ${_swapFile})
# Make sure swapfile is less as a quarter of free space
if [[ ${_gbFree} -le $(($_gb * 4)) ]] ; then
giveError "Not enough space for swap file ($_gb, ${_gbFree})"
fi
When you need the output of a command you use $(command).
I defined the function getFreeGB to get the free GB on a partition:
function getFreeGB {
df -BG $(dirname $1) | \
tail -n 1 | \
awk '{print substr($4, 1, length($4) - 1)}'
}
With 'df -BG' the output is in gigabytes.
Recommended by LinkedIn
I am only interested in the last line, so I use tail -n 1.
The free space is the fourth field that is output and I need to remove the G. That is where the awk command is for.
I defined the function giveError for when something goes wrong:
function giveError {
echo $1
exit 1
}
Before that I do some more checks:
if [[ $(id --user) -ne 0 ]] ; then
giveError "${_scriptName} should be run as root"
fi
if [[ $# -ne 2 ]] ; then
giveError "ERROR: ${_scriptName} SWAPFILE GB"
fi
declare -r _swapFile=$1
declare -ir _gb=$2
if [[ -e ${_swapFile} ]] ; then
giveError "${_swapFile} already exists"
fi
I also need the name of the script:
declare -r _scriptName=$(basename ${0})
And I start my scripts with:
#!/usr/bin/env bash
set -o errexit
set -o nounset
This makes sure that bash is found. The executable can be located in different places on different systems.
I also want the script to terminate on an error and an unset variable be an error.
I am curious what you think about this script and if you like me to share other scripts and what kind of scripts.
Is my explanation a bit sparse, or to broad?
You can get the script here: addSwapFile.sh.
There was a problem with the link to the script, but that is now solved.