1
\$\begingroup\$

With Kubuntu 22.04 ...

Questions :

  1. What is a better way than using 2 cases?

    The 1st case, script Line 48 "case $x in" lets user choose to clear screen or not clear.

    The 2nd case, script Line 86 "case $x in" performs the task, like bytes free.

  2. Any wrong field choices? that represent bytes free

  3. Any wrong field choices? that represent bytes used

  4. Any wrong field choices? that represent bytes size of drive

    Example:
    DISK_SIZE_FREE_BB=$(df . -B1 |tail -n1 |awk '{print $4}') What is a better way to get available (free) disk space?
    df . -B1 |tail -n1 |awk '{print $4}'


Sample output 1

  c) clear screen, Checking disk space: free, used, size & Converting B MiB GiB GB TB
  m) clear screen, checking free disk space Method 1 2 3
  p) clear screen, Partition size & overhead 
  k)  keep screen, no clear, then run   c   above.
      enter a Letter

Sample output 2

Type=part   Path_Part.=/dev/sdc1   Directory=/media/u3/sExt4_1863G   File System type=ext4 
Checking disk space: free, used, size & Converting B MiB GiB GB TB

   128154107904 bytes free, method 3                             128,154,107,904
  1739655225344 bytes used                                     1,739,655,225,344
  1967845998592 bytes size                                     1,967,845,998,592

        122218M bytes free     ~ MiB x 1,048,576 
       1659065M bytes used     ~ MiB x    "     
       1876685M bytes size     ~ MiB x    "     

           120G bytes free     ~ GiB x 1,073,741,824         128.1 GB bytes free 
          1621G bytes used     ~ GiB x    "                 1739.6 GB bytes used 
          1833G bytes size     ~ GiB x    "                 1967.8 GB bytes size 

            .1T bytes free     ~
           1.7T bytes used     ~
           1.9T bytes size     ~

           6.5% bytes free     ~
          88.4% bytes used     ~ 94% used, reserved blocks + ...
             _% overhead
         100.0% bytes size

script

#!/bin/bash  
# FreeDiskSpace_v1a.sh   version 1a   Tested on Kubuntu 22.04 
# Purpose:  need to know available (free) bytes before backing-up to this Path + more. 
# How to run script from an absolute path ? See line below ... 
# bash /home/x_/Desktop/FreeDiskSpace_v1a.sh 



sync 

DISK_SIZE_FREE_BB=$(df . -B1 |tail -n1 |awk '{print $4}')
DISK_SIZE_FREE_GM=$(df . -BM |tail -n1 |awk '{print $4}')
DISK_SIZE_FREE_GB=$(df . -BG |tail -n1 |awk '{print $4}')


DISK_SIZE_USED_BB=$(df . -B1 |tail -n1 |awk '{print $3}')
DISK_SIZE_USED_GM=$(df . -BM |tail -n1 |awk '{print $3}')
DISK_SIZE_USED_GB=$(df . -BG |tail -n1 |awk '{print $3}')


DISK_SIZE_TOTAL_B=$(df . -B1 |tail -n1 |awk '{print $2}')
DISK_SIZE_TOTAL_M=$(df . -BM |tail -n1 |awk '{print $2}')
DISK_SIZE_TOTAL_G=$(df . -BG |tail -n1 |awk '{print $2}')


DISK_PERCENT_USED=$(df . -B1 |tail -n1 |awk '{print $5}') 





# to clear screen or not to clear screen then run script 
msg1="c) clear screen, Checking disk space: free, used, size & Converting B MiB GiB GB TB"
msg2="m) clear screen, checking free disk space Method 1 2 3"
msg3="p) clear screen, Partition size & overhead " 
msg4="k)  keep screen, no clear, then run   c   above." 
msg5="    enter a Letter" 

msg1b="Checking disk space: free, used, size & Converting B MiB GiB GB TB" 

echo "  $msg1"
echo "  $msg2"
echo "  $msg3"
echo "  $msg4"
echo "  $msg5"

read -rn 1 x 
case $x in
  c) clear;;
  #reset ; clear && printf '\e[3J' 
  m) clear;;
  p) clear;;
  k) echo " keep screen";;
  *) echo "  invalid character  Use lower case   try again";echo ;exit 1;; 
esac



#Header start for above case clauses 
Path_Part=$(df . -hT |tail -n1 |awk '{print $1}') 

tput setaf  7 ;echo "Type=" |tr '\n' '\0' 
tput setaf 12 ; lsblk "$Path_Part" -ae7 -oType,name,path,size |tail -n1 |awk '{print $1}' |tr '\n' ' ' 

tput setaf  7 ;echo "  Path_Part.=" |tr '\n' '\0'  
tput setaf 12 ; df . -hT |tail -n1 |awk '{print $1}' |tr '\n' ' '

tput setaf  7 ;echo "  Directory=" |tr '\n' '\0'  
tput setaf 12 ;pwd |tr '\n' ' ' 

tput setaf  7 ;echo "  File System type=" |tr '\n' '\0'  
tput setaf 12 ; df . -hT |tail -n1 |awk '{print $2}' |tr '\n' ' ' 

tput setaf  7 ;echo 
#Header end 









#     x   in above case clauses carries over to this 2nd case section 
case $x in
  c) ;; # Goto code after case clauses 
  k) ;;

  

  
  
  
  
  
  
  
  
  
  
  
  
  
# m) clear screen, checking free disk space Method 1 2 3"  
  m)
sync 
echo "$msg2" ;echo   

printf '%15s' "$(($(stat . -f --format="%a*%S")))"    |tr '\n' ' ' ;echo " bytes free method 1  =   echo \$((\$(stat . -f --format="%a*%S"))) "

printf '%15s' "$(df . -B1 --output=avail |tail -n 1)" |tr '\n' ' ' ;echo ' bytes free method 2  =   df . -B1 --output=avail |tail -n 1 ' 

v1=$(($(stat . -f --format="%a*%S")))         # variable   1
v2=$(df . -B1 --output=avail |tail -n 1)      # variable   2
d1=$(echo -n $((v1-v2)))                      # difference 1 

printf '%15s' "$(echo "$d1" |tr '\n' ' ' )" ;echo " bytes differ, 0 is ideal"  ;echo
read -rsn1     -p  "Press any key to continue . . ." ; echo  







printf '%15s' "$(df . -B1 --output=avail |tail -n 1)"   |tr '\n' ' ' ;echo ' bytes free method 2  =   df . -B1 --output=avail |tail -n 1 ' 

printf '%15s' "$(df . -B1 |tail -n1 |awk '{print $4}')" |tr '\n' ' ' 
echo " bytes free method 3  =   df . -B1 |tail -n1 |awk '{print \$4}'" 

v3=$(df -B1 .   |tail -n1 |awk '{print $4}')   # variable   3 
d2=$(echo -n $((v2-v3)))                       # difference 2 

printf '%15s' "$(echo "$d2" |tr '\n' ' ' )" ;echo " bytes differ, 0 is ideal"  ;echo 
read -rsn1     -p  "Press any key to continue . . ." ;echo ;echo    










if [ "$d1" -eq "$d2" ] 
  then 
  echo "Same result for above 3 methods. "
  echo "Confirming bytes free 3 ways. "
  echo "Not all distros have --output=avail "
  echo "df  likely portable. "
  echo "Purpose:  need to know available (free) bytes before backing-up to this Path." 
  else 
echo "differ, Bad.  Run script again or Check manually. " 
  fi
echo 
read -rsn1     -p  "Press any key to continue . . ." 
echo;;




  
  
  
  
# p) clear screen, Partition size & overhead "   
  p) 
sync 
echo "$msg3"
echo 
DISK_PARTITN_DISK=$(df . -hT   |tail -n1 |awk '{print $1}') 
#                  sudo parted /dev/sdb1          unit B print 
#                  sudo parted /dev/nvme0n1p2     unit B print 
DISK_PARTITN_SIZE="$(sudo parted "$DISK_PARTITN_DISK" unit B print |grep 'Disk /dev/' |awk '{print $3}' |tr -d 'B' )"

printf '%17s' "$(bc <<< "scale=0; ($DISK_PARTITN_SIZE/1000000000)")" |tr '\n' ' ' ;echo " GB    Partition size or" ;echo











p1=$DISK_PARTITN_SIZE
p2=$DISK_SIZE_TOTAL_B
p3=$(echo -n $((p1-p2)))                       # difference 

printf '%17s' "$(echo "$p1")" ' bytes Partition size';echo 

printf '%17s' "$(echo "$p2")" ' bytes capacity filesystem ';echo 

printf '%17s' "$(echo "$p3")" ' bytes overhead, difference ( Paritiion size - capacity filesystem ) or ';echo ;echo

printf '%17s' "$(bc <<< "scale=3; ($p3/1000000)")"    |tr '\n' ' ' ;echo " MB    overhead, difference ( Paritiion size - capacity filesystem ) or " 

printf '%17s' "$(bc <<< "scale=3; ($p3/1000000000)")" |tr '\n' ' ' ;echo " GB    overhead, difference ( Paritiion size - capacity filesystem ) " 

printf '%17s' "$(printf '%.9f\n' "$(echo "100*(""$p3""/""$p1"")" |bc -l)")" |tr '\n' ' '  ;echo  " %     overhead, difference / Paritiion size x 100 " ;echo




printf "%17s" "overhead" " ~ reserved blocks + ..."  ;echo

printf "%17s" "reserved blocks" " = sudo dumpe2fs -h /dev/sd_3 |grep -i 'reserved' #   for ext4"
echo 
echo "                                                                   not for vfat or fuseblk"
echo "                                                                   (NTFS or exFat)  expect" 
echo "                                                                   Bad magic number ..."
sudo dumpe2fs -h "$Path_Part" |grep -i 'reserved'
echo 

exit 1;;









  
  
  *) echo "  invalid option, try again ";;
esac

# above : end of all case clauses 





# below : Checking disk space: free, used, size & Converting B MiB GiB GB TB
sync 

tput setaf  7 ;echo "$msg1b" ;echo

printf '%15s' "$(echo "${DISK_SIZE_FREE_BB}")" |
tr '\n' ' ' ;echo " bytes free, method 3     " |tr '\n' ' ' 
printf '%38s' "$(numfmt --g "${DISK_SIZE_FREE_BB}")" ;echo 


printf '%15s' "$(echo "${DISK_SIZE_USED_BB}")" |
tr '\n' ' ' ;echo " bytes used               " | tr '\n' ' ' 
printf '%38s' "$(numfmt --g "${DISK_SIZE_USED_BB}")" ;echo


printf '%15s' "$(echo "${DISK_SIZE_TOTAL_B}")" |
tr '\n' ' ' ;echo " bytes size               " |tr '\n' ' ' 
printf '%38s' "$(numfmt --g "${DISK_SIZE_TOTAL_B}")" ;echo 




echo   #Mega bytes
printf '%15s' "$(echo "${DISK_SIZE_FREE_GM}")" " bytes free     ~ MiB x 1,048,576 " ;echo
printf '%15s' "$(echo "${DISK_SIZE_USED_GM}")" " bytes used     ~ MiB x    \"     " ;echo 
printf '%15s' "$(echo "${DISK_SIZE_TOTAL_M}")" " bytes size     ~ MiB x    \"     " ;echo 

















echo   #Giga bytes
printf '%15s' "$(echo "${DISK_SIZE_FREE_GB}")" " bytes free     ~ GiB x 1,073,741,824" |
tr '\n' ' ' ; printf '%14s' "$(bc <<< "scale=1; ($DISK_SIZE_FREE_BB/1000000000)")" |
tr '\n' ' ' ;echo " GB bytes free "

printf '%15s' "$(echo "${DISK_SIZE_USED_GB}")" " bytes used     ~ GiB x    \"         "| 
tr '\n' ' ' ; printf '%14s' "$(bc <<< "scale=1; ($DISK_SIZE_USED_BB/1000000000)")" | 
tr '\n' ' ' ;echo " GB bytes used "


printf '%15s' "$(echo "${DISK_SIZE_TOTAL_G}")" " bytes size     ~ GiB x    \"         "|
tr '\n' ' ' ; printf '%14s' "$(bc <<< "scale=1; ($DISK_SIZE_TOTAL_B/1000000000)")" | 
tr '\n' ' ' ;echo " GB bytes size "











echo   #Tera bytes
printf '%14s' "$(bc <<< "scale=1; ($DISK_SIZE_FREE_BB/1000000000000)")" |tr '\n' ' ' ;echo "T bytes free     ~"
printf '%14s' "$(bc <<< "scale=1; ($DISK_SIZE_USED_BB/1000000000000)")" |tr '\n' ' ' ;echo "T bytes used     ~"
printf '%14s' "$(bc <<< "scale=1; ($DISK_SIZE_TOTAL_B/1000000000000)")" |tr '\n' ' ' ;echo "T bytes size     ~"



echo   #Percents %
printf '%14s' "$(printf '%.1f\n' "$(echo "100*(""$DISK_SIZE_FREE_BB""/""$DISK_SIZE_TOTAL_B"")" | bc -l)")" |tr '\n' ' ' ;echo "% bytes free     ~" 


printf '%14s' "$(printf '%.1f\n' "$(echo "100*(""$DISK_SIZE_USED_BB""/""$DISK_SIZE_TOTAL_B"")" | bc -l)")" |tr '\n' ' ' ;echo "% bytes used     ~" |
tr '\n' ' ' ;echo "$DISK_PERCENT_USED" "used, reserved blocks + ..."

echo        "             _% overhead" 
                                 
printf '%14s' "$(printf '%.1f\n' "$(echo "100*(""$DISK_SIZE_TOTAL_B""/""$DISK_SIZE_TOTAL_B"")" | bc -l)")" |tr '\n' ' ' ;echo "% bytes size     " 
echo 




# Units of Measure & Bytes
# Kilobyte (KB)  1000¹ = 1,000
# Megabyte (MB)  1000² = 1,000,000
# Gigabyte (GB)  1000³ = 1,000,000,000
# Terabyte (TB)  1000⁴ = 1,000,000,000,000
# Petabyte (PB)  1000⁵ = 1,000,000,000,000,000
# Kibibyte (KiB) 1024¹ = 1,024
# Mebibyte (MiB) 1024² = 1,048,576
# Gibibyte (GiB) 1024³ = 1,073,741,824
# Tebibyte (TiB) 1024⁴ = 1,099,511,627,776
# Pebibyte (PiB) 1024⁵ = 1,125,899,906,842,624   


# Copyright April 2023
# FreeDiskSpace_v1a.sh
#
# This script was tested on:
# 1.  Kubuntu 22.04
#
# This script was tested on shellcheck:
# 2.  https://www.shellcheck.net/
#     errors listed may not be errors, for example: 
#     ^-- SC2116 (style): Useless echo? Instead of 'cmd $(echo foo)', just use 'cmd foo'.


# This program is free software:
# you can redistribute it and/or modify
# it under the terms of the GNU General Public License as
# published by the Free Software Foundation, 
# either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY;
# without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details. 
#
# You should have received a copy of the
# GNU General Public License along with this program.
# If not, see
# http://www.gnu.org/licenses/

# Software Disclaimer
# There are inherent dangers in the use of any software available for 
# download on the Internet, and we caution you to make sure that you 
# completely understand the potential risks before downloading any of the software.
#
# The Software and code samples available on this website are 
# provided "as is" without warranty of any kind, either express or implied. 
# Use at your own risk.
#
# The use of the software and scripts downloaded on this site is done at 
# your own discretion and 
# risk and 
# with agreement that you will be solely responsible for 
# any damage to your computer system or loss of data that 
# results from such activities. You are solely responsible for 
# adequate protection and backup of the data and 
# equipment used in connection with any of the software, and 
# we will not be liable for any damages that you may suffer in 
# connection with using, modifying or distributing any of this software. 
# No advice or information, whether oral or written, obtained by you from us or 
# from this website shall create any warranty for the software.
#
#
# We make no warranty that the software will meet your requirements.
#
# We make no warranty that the software will be 
# uninterrupted, timely, secure or error-free.
#
# We make no warranty that the results that may be obtained from the 
# use of the software will be effective, accurate or reliable. 
#
# We make no warranty that the quality of the software will meet your expectations.
#
# We make no warranty that any errors in the software obtained from us 
# will be corrected.
#
# The software, code sample and their documentation made available on this website:
# could include technical or other mistakes, inaccuracies or typographical errors. 
# We may make changes to the software or documentation made available on 
# its web site at any time without prior-notice.
# 
# The software may be out of date, and we make 
# no commitment to update such materials.
# We assume no responsibility for errors or omissions in the 
# software or documentation available from its web site.
#
# In no event shall we be liable to you or any third parties for 
# any special, punitive, incidental, indirect or consequential damages of any kind, 
# or any damages whatsoever, including, without limitation, 
# those resulting from loss of use, data or profits, and 
# on any theory of liability, arising out of or in connection with the 
# use of this software.
#
# Under sell.  Over deliver. 
# 
# Use this script at your own risk.
# 
# This script might cause your computer to melt-down plus 300 mega bytes. 
#  i have no understanding of what is really happening behind the scenes.
# We have no understanding of what is really happening behind the scenes.
#  i have no understanding of the actual process behind each command.
# We have no understanding of the actual process behind each command.
#  i have no understanding of the Kernel.
# We have no understanding of the Kernel.
# Yes, there are observed effects.  
# But, the paper map is not the territory.  
# 
# Use this script at your own risk.
#
#
#
#        version 1a
# FreeDiskSpace_v1a.sh
# posted 9-April-2023
# 
\$\endgroup\$
1
  • 2
    \$\begingroup\$ I find the script hard to read as presented. Does the above truthfully present working code from your project? (First obstacle is excessive vertical spacing.) \$\endgroup\$
    – greybeard
    Commented Apr 23, 2023 at 20:12

2 Answers 2

3
\$\begingroup\$

This script is poorly documented.

No unit tests appear as part of this submission.

In the identifier DISK_SIZE_FREE_GM, I have no idea what GM denotes. BB is apparently "bytes", and GB is apparently binary "GiB" (or perhaps decimal "GB" gigabytes). But "GM" is obscure, it is a poorly chosen identifier. Prefer to use names that correspond to SI, or at least add a # comment to help the Gentle Reader interpret what you wrote.


You mentioned lines 48 and 86. From the OP it is unclear which bits of source code correspond to those. Consider posting the URL of a GitHub file.


Implicit in all this is that there is some motivating Use Case or Specification that the code should adhere to. Yet we find no unit tests, no comments documenting what correct inputs and correct outputs would be. One can only report a bug w.r.t. written specifications. Absent that, I can only say, "well, this runs without segfaulting." So, I guess it is correct.


Let me respond to each of your queries in sequence.

What is a better way than using 2 cases?

I have no idea. You offered neither a specification nor unit tests.

Any wrong field choices? that represent bytes free

I have no idea. You offered neither a specification nor unit tests.

Any wrong field choices? that represent bytes used

I have no idea. You offered neither a specification nor unit tests.

Any wrong field choices? that represent bytes size of drive

I have no idea. You offered neither a specification nor unit tests.

tl;dr:

Software engineering is a team sport. There is a collaboration, where we expect to draw upon the strengths of each participant. To do that, you have to give as much as you receive. To offer a poorly specified Use Case and Public API yet expect a high quality software product is to live in a fantasy land where GPT3 will satisfy all your customer expectations. I do not understand how this submission rises to the level where we would expect that the PR process would produce a feature branch that is ready to merge down to main. Recommend that you coordinate with the stake holders and re-evaluate the best set of technical goals for delivering value to the business. Merge this down only after obtaining a second opinion.


Would I delegate maintenance tasks on this codebase to collaborators?

No.

Would I accept maintenance tasks on this codebase?

No.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ "Consider posting the URL of a GitHub file." Questions should be self-contained. If specific lines need work, there are other ways to refer to them. Hosting them externally is not preferred and can even cause problems. \$\endgroup\$
    – Mast
    Commented Apr 10, 2023 at 21:11
  • 1
    \$\begingroup\$ There are only 2 lines mentioning case $x in, it should be clear which lines are intended here. \$\endgroup\$
    – Mast
    Commented Apr 10, 2023 at 21:12
1
\$\begingroup\$

Please don't use all-caps for shell variable names. This is a convention for environmental variables to be passed to child processes, and each one you use increases the chances of unexpected behaviour change.

Those ten variables get their values from ten different invocations of df at different times. If you expect their values to be consistent, you could be surprised.

Instead of using awk to extract fields from the df output, consider using --output (assuming GNU df - this is evident from later uses) to produce only the desired fields in output.

Instead of reading input interactively, consider being friendlier to your users and accept the choice of action as an argument. That makes it easier to use your program in a pipeline or other non-interactive context such as a cron job.

Instead of piping echo into tr to remove newlines, consider using printf instead. In any case, prefer not to write null characters (\0) to output streams without good reason.

The second case has some huge code blocks, and the (lack of) indentation makes it very difficult to follow the control flow. Either indent properly, or encapsulate those large blocks into functions - preferably do both.

It seems silly to print longer strings into a fixed-width format here:

printf '%17s' "$(echo "$p1")" ' bytes Partition size';echo 

printf '%17s' "$(echo "$p2")" ' bytes capacity filesystem ';echo

Since ' bytes Partition size' and ' bytes capacity filesystem ' are both longer than 17 characters, they are obviously going to overspill their columns. But it looks like all we wanted was simply:

printf '%17d bytes Partition size\n' "$p1"
printf '%17d bytes capacity filesystem\n' "$p2"

Be careful writing user-facing messages - I guess the four mentions of "Paritiion" were intended to be "Partition", for example.

Please ensure that error messages go to standard error stream (>&2) rather than the output stream.

Avoid invoking sudo from within scripts. That's an interactive tool, which may ask for one or more passwords when run. If a script does that, how is a user to know that the request is genuine? It's better to assume (or check) that the process is already sufficiently privileged, perhaps even dropping privileges where possible. Then an unprivileged user is able to use sudo explicitly to run it if necessary (and only need to enter credentials just once).

Your trailing comment contains this:

# This script was tested on shellcheck:
# 2.  https://www.shellcheck.net/
#     errors listed may not be errors, for example: 
#     ^-- SC2116 (style): Useless echo? Instead of 'cmd $(echo foo)', just use 'cmd foo'.

Although that's not an error, it's wasteful and convoluted - why not just fix those warnings? That would make the code a little more readable, at least.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.