{"id":10960,"date":"2025-06-24T03:00:00","date_gmt":"2025-06-24T07:00:00","guid":{"rendered":"https:\/\/www.both.org\/?p=10960"},"modified":"2026-02-04T14:56:39","modified_gmt":"2026-02-04T19:56:39","slug":"do-i-have-enough-space-for-that","status":"publish","type":"post","link":"https:\/\/www.both.org\/?p=10960","title":{"rendered":"Do I have enough space for that?"},"content":{"rendered":"<div class=\"pld-like-dislike-wrap pld-template-1\">\r\n    <div class=\"pld-like-wrap  pld-common-wrap\">\r\n    <a href=\"javascript:void(0)\" class=\"pld-like-trigger pld-like-dislike-trigger  \" title=\"\" data-post-id=\"10960\" data-trigger-type=\"like\" data-restriction=\"cookie\" data-already-liked=\"0\">\r\n                        <i class=\"fas fa-thumbs-up\"><\/i>\r\n                <\/a>\r\n    <span class=\"pld-like-count-wrap pld-count-wrap\">    <\/span>\r\n<\/div><\/div>\n<p>Let&#8217;s say I have several copies of a system: it doesn&#8217;t really matter what this system is, I think this describes fairly well how many production environments are set up. If it makes you happy to have a concrete example, let&#8217;s say this is a server-based Java application.<\/p>\n\n\n\n<p>In this system, <em>dev<\/em> is the next version the application development team is working on, <em>prod<\/em> is the version that&#8217;s in production use now, and <em>prod.old<\/em> is the previous version from production that we need to keep as a backup. We also have separate <em>test<\/em> and <em>staging<\/em> areas that we use when new versions are ready to come out of development, but before we put them into production.<\/p>\n\n\n\n<p>When the QA team has approved the new version to move into production, we need to keep the <em>staging<\/em> system where it is (not just rename it) because we need to validate that the production version matches the staging version. In the end, the process to move a version from staging into production looks like this:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Delete the <em>prod.old<\/em> version<\/li>\n\n\n\n<li>Rename <em>prod<\/em> to <em>prod.old<\/em><\/li>\n\n\n\n<li>Copy <em>staging<\/em> to <em>prod<\/em><\/li>\n<\/ol>\n\n\n\n<p>Over time, the disk starts to fill up. When space becomes a premium, how can your script detect <em>if it has enough space to do the job<\/em> so it can abort if there isn&#8217;t enough room?<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"how-much-space\">How much space<\/h2>\n\n\n\n<p>Unix and Unix-like systems (such as Linux) provide two commands that help you understand how much space is being used:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>du<\/strong> (&#8220;disk usage&#8221;) counts how much disk space is used by a directory<\/li>\n\n\n\n<li><strong>df<\/strong> (&#8220;disk free&#8221;) reports how much disk space is used (and is available) on a filesystem<\/li>\n<\/ul>\n\n\n\n<p>I&#8217;ve set up a very tiny virtual disk to demonstrate how to use these commands. This disk is mounted on the <code>\/mnt<\/code> directory, and I already set up the <em>dev<\/em>, <em>test<\/em>, <em>staging<\/em>, <em>prod<\/em> and <em>prod.old<\/em> directories to mimic the application environment I described:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ pwd\n\/mnt\/app\n\n$ ls\ndev  prod  prod.old  staging  test<\/code><\/pre>\n\n\n\n<p>We can use the <strong>du<\/strong> command to count the disk space used in a file or directory. I want to know how much space is used within the directory, so I&#8217;ll add the <strong>-s<\/strong> option to display only a summary for each directory:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ du -s *\n696 dev\n682 prod\n671 prod.old\n693 staging\n693 test<\/code><\/pre>\n\n\n\n<p>By default, these sizes are reported in 1 KB blocks, but you can put this into &#8220;human readable&#8221; form by adding the <strong>-h<\/strong> option:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ du -sh *\n696K    dev\n682K    prod\n671K    prod.old\n693K    staging\n693K    test<\/code><\/pre>\n\n\n\n<p>You&#8217;ll note that each new version gets larger and larger over time: <em>dev<\/em> is slightly larger than the previous version in <em>test<\/em> and <em>staging<\/em>, <em>staging<\/em> takes more space than the <em>prod<\/em> version, and <em>prod<\/em> is a little bigger than the older <em>prod.old<\/em> version.<\/p>\n\n\n\n<p>To see how much space is available on the filesystem, we use the <strong>df<\/strong> command. You can specify the filesystem path like <code>\/mnt<\/code> to view that filesystem, or you can use <code>.<\/code> to mean the filesystem that contains the current path. In this case, I&#8217;m running the command from <code>\/mnt\/app<\/code> and my very tiny disk is mounted at the <code>\/mnt<\/code> path:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ df .\nFilesystem     1K-blocks  Used Available Use% Mounted on\n\/dev\/loop0          3752  3455        41  99% \/mnt<\/code><\/pre>\n\n\n\n<p>There&#8217;s not much space left, just 41 KB. When it&#8217;s time to move the new version into production, will there be enough space to do that after I delete the <em>prod.old<\/em> version, rename <em>prod<\/em> to <em>prod.old<\/em>, then copy <em>staging<\/em> to <em>prod<\/em>?<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"the-simple-version\">The simple version<\/h2>\n\n\n\n<p>Being good systems administrators who want to automate everything, we should create a script to perform all the actions to move a new version into production. A simple version of this script might look like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#!\/bin\/bash\n\ncd \/mnt\/app\n\nrm -rf prod.old\nmv prod prod.old\ncp -r staging prod<\/code><\/pre>\n\n\n\n<p>But this script doesn&#8217;t have any &#8220;smarts&#8221; to know if there will be enough space to do all of this work. We need to account for <em>removing the old prod.old<\/em> and <em>copying the new staging<\/em>. Let&#8217;s explore some options to do that:<\/p>\n\n\n\n<p>The GNU version of the <strong>df<\/strong> command (which is the version available on pretty much every Linux system) lets you give a <em>field name<\/em> to specify what value you want to report on. Valid names are <code>source<\/code>, <code>fstype<\/code>, <code>itotal<\/code>, <code>iused<\/code>, <code>iavail<\/code>, <code>ipcent<\/code>, <code>size<\/code>, <code>used<\/code>, <code>avail<\/code>, <code>pcent<\/code>, <code>file<\/code> and <code>target<\/code>. I&#8217;m most interested in the <code>avail<\/code> value, because that tells me <em>how much space is left<\/em> on the filesystem. I can use that to calculate if I&#8217;ll have enough room left after migrating the new version into production.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ df --output=avail .\nAvail\n   41<\/code><\/pre>\n\n\n\n<p>The <strong>df<\/strong> command doesn&#8217;t have an option to <em>not display<\/em> the header line, but you can use the <strong>tail<\/strong> command to just print the last line, containing the number. In a Bash script, we might get the value like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>avail=$(df --output=avail . | tail -n 1)<\/code><\/pre>\n\n\n\n<p>How much space will we free up by removing the old <em>prod.old<\/em> version? We can answer that with the <strong>du<\/strong> command:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ du -s prod.old\n671 prod.old<\/code><\/pre>\n\n\n\n<p>To automate this in a Bash script, we only need the first field, which is the number portion. We can use the <strong>awk<\/strong> command to print just the number, which is useful when storing this value in a Bash script:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>old=$(du -s prod.old | awk '{print $1}')<\/code><\/pre>\n\n\n\n<p>The steps are the same to determine how much space is needed to copy <em>staging<\/em> into the new <em>prod<\/em> version:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ du -s staging\n693 staging<\/code><\/pre>\n\n\n\n<p>Or, for the Bash script:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>staging=$(du -s staging | awk '{print $1}')<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"look-at-the-numbers\">Look at the numbers<\/h2>\n\n\n\n<p>Using <strong>du<\/strong> and <strong>df<\/strong>, we know the <code>\/mnt<\/code> filesystem currently has 41 KB free. That&#8217;s not a lot. To move a new version of the application into production, we&#8217;ll first remove the <em>prod.old<\/em> directory, which should free up 671 KB, or a total of 712 KB free. Then, we&#8217;ll rename <em>prod<\/em> to <em>prod.old<\/em> and make a copy of the <em>staging<\/em> directory to become the new <em>prod<\/em> directory. Making the copy requires 693 KB, which means I&#8217;d expect to have 19 KB free at the end.<\/p>\n\n\n\n<p>One way to do this calculation is with the <strong>expr<\/strong> command, which evaluates simple math expressions. Just type the calculation the way you&#8217;d enter it into a calculator:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ expr 41 + 671 - 693\n19<\/code><\/pre>\n\n\n\n<p>We can add this to the Bash script to detect if there&#8217;s enough room on the filesystem before we delete or copy anything:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#!\/bin\/bash\n\ncd \/mnt\/app\n\navail=$(df --output=avail . | tail -n 1)\nold=$(du -s prod.old | awk '{print $1}')\nstaging=$(du -s staging | awk '{print $1}')\n\nfree=$(expr $avail + $old - $staging)\n\nif &#91; \"$free\" -le 0 ] ; then\n  echo 'abort -- not enough space'\n  exit 1\nfi\n\nrm -rf prod.old\nmv prod prod.old\ncp -r staging prod<\/code><\/pre>\n\n\n\n<p>This does all the math to determine if there&#8217;s enough free space. After the math is done, a negative or zero value indicates that there won&#8217;t be enough space left on the filesystem to do all of the work; if so, the Bash script prints an error and quits.<\/p>\n\n\n\n<p>If I instead wanted to make sure there was <em>a little room<\/em> left on the filesystem after copying everything, like 1% so I could edit configuration files, we can compare the result to a calculation of percent. 1% is pretty easy to calculate, because we just need to divide the total filesystem size by 100. We can get the filesystem system with the <code>size<\/code> field in the <strong>df<\/strong> command:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ df --output=size .\n1K-blocks\n     3752<\/code><\/pre>\n\n\n\n<p>Using this, we can make one final update to the script:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#!\/bin\/bash\n\ncd \/mnt\/app\n\navail=$(df --output=avail . | tail -n 1)\nold=$(du -s prod.old | awk '{print $1}')\nstaging=$(du -s staging | awk '{print $1}')\n\nfree=$(expr $avail + $old - $staging)\n\nsize=$(df --output=size . | tail -n 1)\nminfree=$(expr $size \/ 100)\n\nif &#91; \"$free\" -le $minfree ] ; then\n  echo 'abort -- not enough space'\n  exit 1\nfi\n\nrm -rf prod.old\nmv prod prod.old\ncp -r staging prod<\/code><\/pre>\n\n\n\n<p>In case you&#8217;re curious, while deleting and copying won&#8217;t completely fill the disk, I&#8217;d have less than 1% free after everything is done. 1% of 3752 KB is 37 KB, and the calculation for free space is 19 KB. So the script would abort and not do the migration for me.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"automate-everything\">Automate everything<\/h2>\n\n\n\n<p>System administrators should <a href=\"https:\/\/www.both.org\/?p=7228\" target=\"_blank\" rel=\"noreferrer noopener\">automate everything<\/a>, which means <a href=\"https:\/\/www.both.org\/?p=7547\" target=\"_blank\" rel=\"noreferrer noopener\">using shell scripts<\/a> to do the steps <em>the same way<\/em> every time you run them. You can prevent failure with a little scripting magic, and ensure that your automated process to copy a new version of a system won&#8217;t fill up the disk.<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>A little scripting goes a long way to make sure you won&#8217;t run out of space with an automated process.<\/p>\n","protected":false},"author":33,"featured_media":3307,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_lmt_disableupdate":"","_lmt_disable":"","footnotes":""},"categories":[149,5,503],"tags":[91,97],"class_list":["post-10960","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-bash","category-linux","category-linux-101","tag-linux","tag-sysadmin"],"modified_by":"David Both","_links":{"self":[{"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts\/10960","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/users\/33"}],"replies":[{"embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=10960"}],"version-history":[{"count":6,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts\/10960\/revisions"}],"predecessor-version":[{"id":10966,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts\/10960\/revisions\/10966"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/media\/3307"}],"wp:attachment":[{"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=10960"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=10960"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=10960"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}