Skip to content

Instantly share code, notes, and snippets.

@theandrewbailey
Created December 11, 2025 01:23
Show Gist options
  • Select an option

  • Save theandrewbailey/30b7be8a8469d72ba4416e2977876948 to your computer and use it in GitHub Desktop.

Select an option

Save theandrewbailey/30b7be8a8469d72ba4416e2977876948 to your computer and use it in GitHub Desktop.
Read entire drive to prove that it's been erased
#! /bin/bash
set -e
function initializeVars(){
declare -i -g gigabyteThreshold=50
dryrun=False
}
initializeVars
function launchTerminal(){ # command
# change terminal for different environments
gnome-terminal -- bash -c "$1; exec bash" &
#xfce4-terminal -e "bash -c '$1; exec bash'"
}
readonly b="\033[1m" # bold text
readonly i="\033[3m" # italic text
readonly n="\033[0m" # normal text
readonly r="\033[0;31m" # red text
readonly u="\033[4m" # underlined text
function errorAndExit(){ # message, error code
echo -e "$r$1$n" >&2
exit $2
}
function validateIntegerOrExit(){ # value, name
if [[ ! $1 =~ ^[1234567890]+$ ]]; then
errorAndExit "Expected integer for $2 but got $1" 64
fi
}
function verifyDrive(){ # /dev/drive
local serial=$(lsblk -dno serial "$1")
local size=$(lsblk -dno size "$1" | tr -d '[:blank:]')
local model=$(lsblk -dno model "$1")
local filename="$serial.txt"
local runcom="sudo dd if="$1" bs=8192 status=progress | hexdump -C | tee -a "$filename""
echo "Verifying $1 ($model, $size) to $filename with:"
echo "$runcom"
if [ $dryrun = False ] ; then
eval $runcom
fi
}
while getopts 'hnd:g:' opt; do case "$opt" in
h)
initializeVars # reset defaults to clear any argument changes
columns=$(tput cols)
echo -e "${b}NAME$n
verifyDrives.sh - Verify drive is erased.
${b}SYNOPSIS$n
verifyDrives.sh [options...]
${b}DESCRIPTION$n
Read entire drive to prove that it's been erased. Will write files with serial numbers of tested drives in the current directory. Works with SATA/SAS (/dev/sd*) and NVMe (/dev/nvme*) drives. Runs this on each drive:
sudo dd if=${i}/dev/drive$n bs=8192 status=progress | hexdump -C | tee -a ${i}serial$n.txt
${b}OPTIONS$n
$b-h$n
Show this and exit.
$b-n$n
Dry run, no op. Identify drives, open extra terminal windows, but don't actually verify drives, or write files.
$b-g$n ${i}integer$n
Set threshold to this many gigabytes. By default, this script will look at all drives that have more than this many gigabytes, and verify each one (in parallel). Default $gigabyteThreshold
$b-d$n ${i}string$n
Verify the specified drive, regardless if it would be caught by the threshold. Called internally by the script.
${b}EXIT STATUS$n
0 if everything happened as expected according to defaults and arguments
64 if an invalid argument was passed
${b}ENVIRONMENT$n
Will launch gnome-terminal. Can easily be switched to xfce4-terminal.
${b}EXAMPLES$n
You're running Ubuntu from a 64 GB USB drive, and don't want to verify the USB drive you're running Ubuntu from:
${b}verifyDrives.sh -g 100$n
/dev/sdw is a small drive below the threshold. Verify it separately:
${b}verifyDrives.sh -d /dev/sdw$n
"|fmt -w $columns
exit 0
;; g)
validateIntegerOrExit "$OPTARG" "-g"
gigabyteThreshold="$OPTARG"
;; n)
dryrun=True
;; d)
if [ -b "$OPTARG" ] ; then
verifyDrive "$OPTARG"
exit 0
else
errorAndExit "$OPTARG is not a block device and won't be verified." 64
fi
;; esac done
readonly threshold=$(( $gigabyteThreshold * 2 ** 30 ))
# when lsblk doesn't support --filter
readonly awkstr="\$2 > $threshold {print \$1}"
readonly drives=$(lsblk -npbldo NAME,SIZE | awk "$awkstr")
for d in $drives; do
size=$(lsblk -dno size "$d" | tr -d '[:blank:]')
model=$(lsblk -dno model "$d")
echo "Verifying $d ($model, $size) in new terminal window..."
if [ $dryrun = False ] ; then
launchTerminal "./$0 -d \"$d\""
else
launchTerminal "./$0 -n -d \"$d\""
fi
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment