So, here is what I have come up with. I am a "qualified" happy with that, but hope others have feedback on where I may have overlooked something.
Purpose/Intent:
-
from Live ISO terminal session, perform partitionning and formatting of a target disk BEFORE starting the installation process, to simplify the activities which the ISO install encompasses.
-
intended as first step of a 3-step process involving
[1] disk formatting (this script),
[2] install of Ubuntu Server, and
[3] use another script which prompts interractively for all User-specified Applications from a list of the most used/cherished Applications available from the Ubuntu distribution repository.
The script offers an option to visually confirm the sequence that will be performed for each line entry in a "layout specification file", before committing to applying that specification to the intended target installation drive.
Everything seems to work fine but, for "partition 4", where I create the partition intended for "root", it reports
parted: invalid token: root
I don't know if that is because an actual root was already mounted, or the fact that the mountpoint path was identified as "/altroot", rather than "/".
Would I get that same error if I was running from a Live Session or not, pre-install of Ubuntu Server setup?
File: partitions_sdc_specs.conf
# partNum:partFsType:partStart:partEnd:partName:partMount:partFlag
1 linux-swap 24KB 4MiB GRUB none null
2 linux-swap 4MiB 64MiB HIBERNATE none swap
3 ext4 64MiB 256MiB BOOT /altboot boot
4 ext4 256MiB 1GiB DB008_F1 /altroot root
5 ext4 1GiB 100% DB008_F2 /DB008_F2 null
The following is a session log of the actual formatting of the drive:
ericthered @ OasisMega1 : /DB001_F4/00__18__DISTRO__Build/001__DiskPartsAndFormats
$ ./001__PreInstallDiskPartitionningAndFormatting.sh --layout "./partitions_sdc_specs.conf" --device "/dev/sdc" --apply
Verifying the specified disk is recognized and accessible ...
Ensuring that the disk has no active dependancy for swap ...
[sudo] password for ericthered:
Confirmed any active SWAP was disabled ...
Ensuring that the disk is not busy or mounted ...
Confirmed /dev/sdc is not mounted ...
Scanning '/dev/sdc' for badblocks before continuing ...
Starting Process of Partitioning and Formatting '/dev/sdc' ...
Create new GPT-type partition table ...
Extract partition data from next entry in specifications array ...
partNum = 1
partFsType = linux-swap
partStart = 24KB
partEnd = 4MiB
partName = GRUB
partMount = none
partFlag = null
Create a partition to specifications using 'parted mkpart ...' ...
Warning: The resulting partition is not properly aligned for best performance: 46s % 2048s != 0s
Update OS awareness of the disk's new structure using 'partprobe' ...
Ensure device node (udev) creation is complete ...
Format partition to specification ...
Setting up swapspace version 1, size = 4 MiB (4165632 bytes)
LABEL='GRUB', UUID=71db8ca8-2ca4-4926-925d-3c378ebe8f1d
/dev/sdc1 8:33 1 4M 0 part
Hit return to continue ...
Extract partition data from next entry in specifications array ...
partNum = 2
partFsType = linux-swap
partStart = 4MiB
partEnd = 64MiB
partName = HIBERNATE
partMount = none
partFlag = swap
Create a partition to specifications using 'parted mkpart ...' ...
Update OS awareness of the disk's new structure using 'partprobe' ...
Ensure device node (udev) creation is complete ...
Format partition to specification ...
mkswap: /dev/sdc2: warning: wiping old swap signature.
Setting up swapspace version 1, size = 60 MiB (62910464 bytes)
LABEL='HIBERNATE', UUID=cb8c2a02-a871-46d9-b455-1095d8435c99
/dev/sdc2 8:34 1 60M 0 part
Hit return to continue ...
Extract partition data from next entry in specifications array ...
partNum = 3
partFsType = ext4
partStart = 64MiB
partEnd = 256MiB
partName = BOOT
partMount = /altboot
partFlag = boot
Create a partition to specifications using 'parted mkpart ...' ...
Update OS awareness of the disk's new structure using 'partprobe' ...
Ensure device node (udev) creation is complete ...
Format partition to specification ...
mke2fs 1.46.5 (30-Dec-2021)
Creating filesystem with 49152 4k blocks and 49152 inodes
Filesystem UUID: ae44c502-de89-41c7-bf9e-7b58611d40c3
Superblock backups stored on blocks:
32768
Allocating group tables: done
Writing inode tables: done
Creating journal (4096 blocks): done
Writing superblocks and filesystem accounting information: done
/dev/sdc3 8:35 1 192M 0 part /altboot
Hit return to continue ...
Extract partition data from next entry in specifications array ...
partNum = 4
partFsType = ext4
partStart = 256MiB
partEnd = 1GiB
partName = DB008_F1
partMount = /altroot
partFlag = root
Create a partition to specifications using 'parted mkpart ...' ...
parted: invalid token: root
Update OS awareness of the disk's new structure using 'partprobe' ...
Ensure device node (udev) creation is complete ...
Format partition to specification ...
mke2fs 1.46.5 (30-Dec-2021)
Creating filesystem with 196608 4k blocks and 49152 inodes
Filesystem UUID: 2af8b0d6-3788-4dd8-95c2-e7399529091c
Superblock backups stored on blocks:
32768, 98304, 163840
Allocating group tables: done
Writing inode tables: done
Creating journal (4096 blocks): done
Writing superblocks and filesystem accounting information: done
/dev/sdc4 8:36 1 768M 0 part /altroot
Hit return to continue ...
Extract partition data from next entry in specifications array ...
partNum = 5
partFsType = ext4
partStart = 1GiB
partEnd = 100%
partName = DB008_F2
partMount = /DB008_F2
partFlag = null
Create a partition to specifications using 'parted mkpart ...' ...
Update OS awareness of the disk's new structure using 'partprobe' ...
Ensure device node (udev) creation is complete ...
Format partition to specification ...
mke2fs 1.46.5 (30-Dec-2021)
Creating filesystem with 3527936 4k blocks and 883008 inodes
Filesystem UUID: d835a150-ffb7-44c7-b2ed-a8dbc0d04599
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208
Allocating group tables: done
Writing inode tables: done
Creating journal (16384 blocks): done
Writing superblocks and filesystem accounting information: done
/dev/sdc5 8:37 1 13.5G 0 part /DB008_F2
Hit return to continue ...
Report final state of disk partitioning ...
Model: USB DISK 2.0 (scsi)
Disk /dev/sdc: 15.5GB
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags:
Number Start End Size File system Name Flags
1 23.6kB 4194kB 4171kB linux-swap(v1) GRUB swap
2 4194kB 67.1MB 62.9MB linux-swap(v1) HIBERNATE swap
3 67.1MB 268MB 201MB ext4 BOOT boot, esp
4 268MB 1074MB 805MB ext4 DB008_F1
5 1074MB 15.5GB 14.5GB ext4 DB008_F2
/dev/sdc 14.5G block:scsi:usb:pci
/dev/sdc1 swap GRUB 71db8ca8-2ca4-4926-925d-3c378ebe8f1d 4M block:scsi:usb:pci
/dev/sdc2 swap HIBERNATE cb8c2a02-a871-46d9-b455-1095d8435c99 60M block:scsi:usb:pci
/dev/sdc3 ext4 BOOT ae44c502-de89-41c7-bf9e-7b58611d40c3 192M /altboot block:scsi:usb:pci
/dev/sdc4 ext4 DB008_F1 2af8b0d6-3788-4dd8-95c2-e7399529091c 768M /altroot block:scsi:usb:pci
/dev/sdc5 ext4 DB008_F2 d835a150-ffb7-44c7-b2ed-a8dbc0d04599 13.5G /DB008_F2 block:scsi:usb:pci
Reload the updated fstab ...
ericthered @ OasisMega1 : /DB001_F4/00__18__DISTRO__Build/001__DiskPartsAndFormats
$
File: 001__PreInstallDiskPartitionningAndFormatting.sh
(Beta Test version of script (looking for feedback)
#!/bin/bash
# SPDX-License-Identifier: GPLv3-or-later
# SPDX-FileCopyrightText: © 2026 Eric Marceau <[email protected]>
#
# For the full text of the GNU General Public License version 3.0 (a.k.a. GPLv3)
# please visit: https://spdx.org/licenses/GPL-3.0-or-later.html
#
#################################################################################################
#################################################################################################
###
### Purpose/Intent:
###
### * from Live ISO terminal session, perform partitionning and formatting
### of a target disk **BEFORE** starting the installation process,
### to simplify the activities which the ISO install encompasses.
###
### * intended as first step of a 3-step process involving
### [1] disk formatting (this script),
### [2] install of Ubuntu Server, and
### [3] use another script which prompts interractively for all User-specified
### Applications from a list of the most used/cherished Applications
### available from the Ubuntu distribution repository.
###
### Version:
### March 27 2026 - Eric Marceau - v0.8 Beta Test
###
#################################################################################################
#################################################################################################
echo="echo -e"
testForDisk()
{
testRoot=$( df -h / | grep '^/' | awk '{ print $1 }' | sed 's+[0-9]*++g' )
testTarget=$( lsblk --paths | grep '^'${DISK} | awk '{ print $1 }' )
test ${doDemo} -eq 1 && ${echo} "\tDEMO: testTarget = '${testTarget}' ..."
if [ -z "${testTarget}" ]
then
${echo} "\n\t ABORT. Specified disk does not exist.\n" ; exit 1
fi
if [ "${testRoot}" = "${testTarget}" ]
then
${echo} "\n\t ABORT. Specified disk is system ROOT.\n" ; exit 1
fi
} #testForDisk()
testForSwap()
{
sudo swapoff ${DISK}?* 2>>/dev/null
testSwaps=$( sudo swapon | grep ${DISK} )
if [ -n "${testSwaps}" ]
then
${echo} "\n\t ABORT. Specified disk has active SWAP. Was unable to turn that off!\n" ; exit 1
else
${echo} "\tConfirmed any active SWAP was disabled ..."
fi
} #testForSwap()
unMountDisk()
{
sudo umount ${DISK}?* 2>>/dev/null
testMounts=$( sudo mount | grep ${DISK} )
if [ -n "${testMounts}" ]
then
${echo} "\n\t ABORT. Specified disk has active mounts. Was unable to unmount partitions!\n" ; exit 1
else
${echo} "\tConfirmed ${DISK} is not mounted ..."
fi
} #unMountDisk()
transient_PartitionSpecificationDefinition()
{
###
### IMPORTANT: NOT meant to be part of permanent script logic
###
###
${echo} "\nCapture Partition Specifications (from command-line or config file) ..."
###
### Guidance:
### - Hibernate target should be system's primary swap to
### minimize delay from copying from swap to hibernate image
### - Hibernate target should be 1.5 to 2 times size of RAM
###
###
### FUTURES:
### - Calculate size of HIBERNATE swap space based on installed RAM
### - Calculate start and end point of each partition based
### size specification for each partition
### - Create fstab entries using UUIDs the resulting disk layout
###
#cat >"${specifications}" <<EnDoFfIlE
## partNum:partFsType:partStart:partEnd:partName:partMount
#1 core 8KB 4MiB GRUB none
#2 swap 4MiB 8GiB HIBERNATE none
#3 ext4 8GiB 12GiB BOOT /boot
#4 ext4 12GiB 200GiB DB007_F1 /
#5 ext4 200GiB 100% DB007_F2 /DB007_F2
#EnDoFfIlE
#cat >"${specifications}" <<EnDoFfIlE
## partNum:partFsType:partStart:partEnd:partName:partMount
#1 linux-swap 4MiB 64MiB HIBERNATE none
#2 ext4 64MiB 256MiB BOOT /altboot
#3 ext4 256MiB 1GiB DB008_F1 /altroot
#4 ext4 1GiB 100% DB008_F2 /DB008_F2
#EnDoFfIlE
cat >"${specifications}" <<EnDoFfIlE
# partNum:partFsType:partStart:partEnd:partName:partMount:partFlag
1 linux-swap 24KB 4MiB GRUB none null
2 linux-swap 4MiB 64MiB HIBERNATE none swap
3 ext4 64MiB 256MiB BOOT /altboot boot
4 ext4 256MiB 1GiB DB008_F1 /altroot root
5 ext4 1GiB 100% DB008_F2 /DB008_F2 null
EnDoFfIlE
if [ ! -s "${specifications}" ]
then
${echo} "\tABORT - unable to create '${specifications}' for demo run.\n" >&2 ; exit 1
fi
} #transient_PartitionSpecificationDefinition()
demoSetup()
{
###
### Call function to create sample partitioning specification
###
transient_PartitionSpecificationDefinition
###
### Create file that will behave as device
###
devFile="/site/DB007_F1/tmp/demo.img"
locn="$(dirname ${devFile} )"
if [ ! -d "${locn}" ]
then
${echo} "\tABORT - unable to access '${locn}/' for demo run.\n" >&2 ; exit 1
fi
${echo} "\n DEMO: Creating '${devFile}' to be used as device file ..."
{
sudo truncate --size 2G ${devFile}
if [ ! -f "${devFile}" ]
then
${echo} "\tABORT - unable to create '${devFile}' for demo run.\n" >&2 ; exit 1
fi
ls -ld ${devFile}
} | awk '{ printf("\t\t%s\n", $0 ) ; }'
###
### Assign first available 'loop' device
###
DISK=$(sudo losetup --verbose --find --partscan --show ${devFile} )
${echo} "\n DEMO: Created simulated drive using loop device '${DISK}' ..."
{
ls -ld ${DISK}
echo ""
df -h -a ${DISK}
#echo "split--"
#mount --verbose | grep ${DISK}
} | awk '{ printf("\t\t%s\n", $0 ) ; }'
}
cleanup()
{
if [ ${doDemo} -eq 1 ]
then
${echo} "\nPurging all elements of demo device ..."
if [ -n "${mounts}" ]
then
#sudo umount --verbose /altboot /altroot /DB008_F2
for mount in $(echo ${mounts} )
do
sudo umount --verbose ${mount}
done
fi
test -n "${DISK}" && { sudo losetup --verbose --detach ${DISK} ; ${echo} "${DISK} detached ..." ; }
test -n "${devFile}" && { sudo rm --verbose --force ${devFile} ; }
${echo} "\tPurged.\n"
fi
}
#################################################################################################
#################################################################################################
trap cleanup EXIT INT TERM
doit=0
doDemo=0
while [ $# -ne 0 ]
do
case "${1}" in
--demo )
doDemo=1
doit=1
shift
;;
--layout )
specifications="${2}"
shift ; shift
;;
--device )
doDemo=0
DISK="${2}"
shift ; shift
;;
--apply )
doit=1
shift ;
;;
esac
done
if [ ${doDemo} -eq 1 ]
then
###
### Specify/Select value for partitioning specifications file
###
specifications="./partitions_demo_specs.conf"
###
### Initialize demo processing session
###
demoSetup
fi
if [ -z "${specifications}" ]
then
echo "\n\t ERROR: File containing specs for device partitioning must be identified using '--layout' flag.\n" ; exit 1
fi
if [ -z "${DISK}" ]
then
echo "\n\t ERROR: Specification of device fullpath required using '--device' flag.\n" ; exit 1
fi
###
${echo} "\nVerifying the specified disk is recognized and accessible ..."
###
CMD="testForDisk"
test ${doit} -eq 1 && { ${CMD} ; }
test ${doit} -eq 0 && { echo "DEFERRED: ${CMD}" ; }
##################################
########## PHASE I ##########
##################################
###
${echo} "\nEnsuring that the disk has no active dependancy for swap ..."
###
CMD="testForSwap"
test ${doit} -eq 1 && { ${CMD} ; }
test ${doit} -eq 0 && { echo "DEFERRED: ${CMD}" ; }
###
${echo} "\nEnsuring that the disk is not busy or mounted ..."
###
CMD="unMountDisk"
test ${doit} -eq 1 && { ${CMD} ; }
test ${doit} -eq 0 && { echo "DEFERRED: ${CMD}" ; }
if [ -n "$(echo ${DISK} | grep -v 'loop' )" ]
then
###
${echo} "\nScanning '${DISK}' for badblocks before continuing ..."
###
CMD="sudo badblocks -nsv ${DISK}"
#test ${doit} -eq 1 && { ${CMD} ; }
test ${doit} -eq 0 && { echo "DEFERRED: ${CMD}" ; }
else
${echo} "\n\tDEMO: Skipping badblocks scan for demo device ..."
fi
##################################
########## PHASE II ##########
##################################
${echo} "\nStarting Process of Partitioning and Formatting '${DISK}' ..."
###
${echo} "\nCreate new GPT-type partition table ..."
###
CMD="sudo parted --script ${DISK} mklabel gpt"
test ${doit} -eq 1 && { ${CMD} ; }
test ${doit} -eq 0 && { echo "DEFERRED: ${CMD}" ; }
#IFSorig="${IFS}"
specsArray=()
export mount=""
indx=0
grep -v '^#' "${specifications}" |
while [ true ]
do
read specsArray[${indx}]
if [ $? -ne 0 ] ; then break ; fi
test ${doDemo} -eq 1 && { ${echo} "\nINPUT: specsArray[${indx}] = ${specsArray[${indx}]} " ; }
###
### Parse partition values from command line or configuration file
###
###
${echo} "\nExtract partition data from next entry in specifications array ..."
###
#IFS=':'
read partNum partFsType partStart partEnd partName partMount partFlag <<< "${specsArray[${indx}]}"
${echo} "\n partNum = ${partNum}
partFsType = ${partFsType}
partStart = ${partStart}
partEnd = ${partEnd}
partName = ${partName}
partMount = ${partMount}
partFlag = ${partFlag}"
###
${echo} "\nCreate a partition to specifications using 'parted mkpart ...' ..."
###
if [ "${partFlag}" = "null" ]
then
#echo "track1"
CMD="sudo parted --script --align optimal ${DISK} mkpart ${partName} ${partFsType} ${partStart} ${partEnd}"
test ${doit} -eq 1 && { ${CMD} ; }
test ${doit} -eq 0 && { echo "DEFERRED: ${CMD}" ; }
else
#echo "track2"
CMD="sudo parted --script --align optimal ${DISK} mkpart ${partName} ${partFsType} ${partStart} ${partEnd} set ${partNum} ${partFlag} on"
test ${doit} -eq 1 && { ${CMD} ; }
test ${doit} -eq 0 && { echo "DEFERRED: ${CMD}" ; }
fi
###
${echo} "\nUpdate OS awareness of the disk's new structure using 'partprobe' ..."
###
CMD="sudo partprobe ${DISK}"
test ${doit} -eq 1 && { ${CMD} ; }
test ${doit} -eq 0 && { echo "DEFERRED: ${CMD}" ; }
sleep 2
###
${echo} "\nEnsure device node (udev) creation is complete ..."
###
CMD="udevadm settle"
test ${doit} -eq 1 && { ${CMD} ; }
test ${doit} -eq 0 && { echo "DEFERRED: ${CMD}" ; }
case ${DISK} in
*loop* )
PARTITION="${DISK}p${partNum}"
;;
/dev/sd* )
PARTITION="${DISK}${partNum}"
;;
* )
PARTITION="${DISK}${partNum}"
;;
esac
###
${echo} "\nFormat partition to specification ..."
###
case ${partFsType} in
core )
;;
linux-swap )
CMD="sudo mkswap ${PARTITION} -L '${partName}'"
test ${doit} -eq 1 && { ${CMD} ; }
test ${doit} -eq 0 && { echo "DEFERRED: ${CMD}" ; }
;;
* )
CMD="sudo mkfs.${partFsType} ${PARTITION} -L '${partName}'"
test ${doit} -eq 1 && { ${CMD} ; }
test ${doit} -eq 0 && { echo "DEFERRED: ${CMD}" ; }
;;
esac
if [ "${partMount}" != "none" ]
then
if [ ! -d "${partMount}" ]
then
CMD="sudo mkdir ${partMount}"
test ${doit} -eq 1 && { ${CMD} ; }
test ${doit} -eq 0 && { echo "DEFERRED: ${CMD}" ; }
if [ ! -d "${partMount}" ]
then
${echo} "\tABORT: Failed to create '${partMount}'.\n" ; exit 1
fi
fi
CMD="sudo mount -t ${partFsType} ${PARTITION} ${partMount}"
RC=0
test ${doit} -eq 1 && { ${CMD} ; RC=$? ; }
test ${doit} -eq 0 && { echo "DEFERRED: ${CMD}" ; }
if [ ${RC} -eq 0 ]
then
mounts="${mounts} ${partMount}"
else
${echo} "\tABORT: Failed to mount '${PARTITION}' at '${partMount}'.\n" ; exit 1
fi
fi
${echo} "\n\t$(lsblk --paths ${PARTITION} | grep '/dev' )" ;
${echo} "\n\t Hit return to continue ...\c" ; read k <&2
indx=$( expr ${indx} + 1 )
done
#IFS="${IFSorig}"
###
${echo} "\nReport final state of disk partitioning ...\n"
###
CMD="sudo parted --script ${DISK} print"
test ${doit} -eq 1 && { ${CMD} | awk '{ printf("\t%s\n", $0 ) }' ; }
test ${doit} -eq 0 && { echo "DEFERRED: ${CMD}" ; }
echo ""
CMD="sudo lsblk --list --path -o NAME,FSTYPE,PARTLABEL,UUID,SIZE,MOUNTPOINT,SUBSYSTEMS"
test ${doit} -eq 1 && { ${CMD} | grep ${DISK} | awk '{ printf("\t%s\n", $0 ) }' ; }
test ${doit} -eq 0 && { echo "DEFERRED: ${CMD}" ; }
###
${echo} "\nReload the updated fstab ..."
###
CMD="sudo systemctl daemon-reload"
test ${doit} -eq 1 && { ${CMD} ; }
test ${doit} -eq 0 && { echo "DEFERRED: ${CMD}" ; }
exit 0
exit 0
exit 0
I am also hoping that the Ubuntu Server install will place the correct "grub2 core.img" in that first partition labelled "GRUB". Can anyone confirm if that will be the case?
May I solicit feedback from the following individuals?
(Order in which names are listed has no significance.)