Partition a Disk Image Safely with sfdisk
One wrong device path with sfdisk turns a partition table into confetti, so this walks through the whole workflow on a disposable file first. You will create a GPT layout inside a 100 MiB image, dry-run it, apply it, then verify and back it up, all without going near a real disk. Budget about fifteen minutes. You need sfdisk from util-linux and enough free space for a small test image; the installed version here is util-linux 2.42.4.
The route
Jump straight to the step you need, or tick off Done means at the end.
Safety boundary
Partition-table changes are destructive. The commands below use a regular file under /tmp, not a block device. Do not replace the image path with /dev/sda, /dev/nvme0n1 or another real device until you have a verified backup and a maintenance plan. Creating a filesystem is a separate operation and is deliberately not included.
1. Confirm the installed tool
Check which executable will actually run and what version it is, before you trust anyone's script, including this one:
$ command -v sfdisk
/home/linuxbrew/.linuxbrew/sbin/sfdisk
$ sfdisk --version
sfdisk from util-linux 2.42.4
Your path will likely differ. The local manual documents GPT, DOS, SUN and SGI labels, script input and the options used here, and it notes that sfdisk aligns starts and ends automatically when you use relative sizes or multiplicative suffixes such as MiB. For portable scripts, let sfdisk pick the starts and express sizes in MiB or GiB rather than raw sector offsets.
2. Create a disposable image
Make a 100 MiB regular file. This touches only the temporary file and needs no elevated privileges:
$ IMAGE=/tmp/sfdisk-demo.img
$ truncate -s 100M "$IMAGE"
$ stat --format='size=%s bytes' "$IMAGE"
size=104857600 bytes
Keep IMAGE set in the same shell for every example below. A regular file is fine for learning and review, but it is not a full stand-in for a kernel block device: there are no partition nodes to mount, and any option about kernel rereads has limited meaning here.
3. Dry-run a GPT script
The input below asks for a GPT label, a 32 MiB Linux partition, then a second partition using whatever is left. The blank start fields let sfdisk handle alignment. L is the documented Linux type shortcut; in GPT output it becomes the Linux filesystem type GUID.
$ printf 'label: gpt\n,32M,L\n,\n' \
| sfdisk --no-act --no-reread "$IMAGE"
Disk /tmp/sfdisk-demo.img: 100 MiB, 104857600 bytes, 204800 sectors
Created a new GPT disklabel
/tmp/sfdisk-demo.imgp1: Created a new partition 1 of type 'Linux filesystem' and of size 32 MiB
/tmp/sfdisk-demo.imgp2: Created a new partition 2 of type 'Linux filesystem' and of size 66 MiB
The partition table is unchanged (--no-act).
The exact disk identifier and some formatting will vary on your machine. What matters is that last unchanged message. --no-act runs the whole operation except the actual write, so this is your chance to catch a wrong size, label or target path before it counts.
4. Apply the reviewed layout
Read the same script again, this time letting it write. --lock=nonblock asks for the recommended device lock but will not wait if another process already holds it. On a real device, use the default blocking lock instead, or stop and investigate a lock failure rather than working around whatever else might be using the disk.
$ printf 'label: gpt\n,32M,L\n,\n' \
| sfdisk --no-reread --lock=nonblock "$IMAGE"
The partition table has been altered.
This is the first command that actually changes anything. On a real block device it can make existing data inaccessible and may notify the kernel about the new table. The manual recommends locking specifically to avoid races with systemd-udevd and similar tools. --no-reread is handy for a regular image like this one; it is not a general fix for changing a mounted or otherwise busy disk.
5. Inspect and verify the result
List the table, then ask sfdisk to check its own consistency:
$ sfdisk --no-reread --list "$IMAGE"
Disklabel type: gpt
Device Start End Sectors Size Type
/tmp/sfdisk-demo.imgp1 2048 67583 65536 32M Linux filesystem
/tmp/sfdisk-demo.imgp2 67584 202751 135168 66M Linux filesystem
$ sfdisk --no-reread --verify "$IMAGE"
/tmp/sfdisk-demo.img:
No errors detected.
Sector numbers are the authoritative detail here. The first partition starts at sector 2048, which lands on a 1 MiB boundary with 512-byte sectors. Note that the last partition doesn't consume the GPT backup area, so the usable size is a touch smaller than the file itself.
For scripts and monitoring, ask for JSON instead of scraping aligned columns:
$ sfdisk --no-reread --json "$IMAGE" \
| jq '.partitiontable.partitions | length'
2
The JSON is output only: sfdisk cannot take JSON as input. No jq? Save the output and inspect it as JSON with whatever tool you already trust.
6. Save a restoreable description
A dump is a text script containing the label, sector geometry, types and partition UUIDs. Save one before making a planned change:
$ sfdisk --no-reread --dump "$IMAGE" > /tmp/sfdisk-demo.dump
$ sed -n '1,12p' /tmp/sfdisk-demo.dump
label: gpt
label-id: ...
device: /tmp/sfdisk-demo.img
unit: sectors
first-lba: 2048
To restore that dump, confirm the target path is really the disposable image, then run sfdisk "$IMAGE" < /tmp/sfdisk-demo.dump. A restore reproduces partition types and UUIDs exactly, so do not clone the same dump onto several machines without thinking about duplicate UUIDs: the manual explicitly warns this can cause problems.
For a binary backup of the sectors holding the table, use --backup-pt-sectors, and keep that raw backup separate from the image. Restoring raw sectors needs dd and an exact device offset, so treat it as an expert recovery operation: verify the device more than once and never improvise the offset from memory.
7. Avoid the common traps
- An omitted start is not sector zero. sfdisk normally chooses the first available aligned sector; the default first start is 1 MiB in.
- An omitted size means as much space as possible. A bare number without a suffix is a sector count;
32Mis a byte value that gets aligned. --label gptdoes not by itself create an empty label. Input containing onlylabel: gptexplicitly requests an empty table; otherwise add partition lines.--forcedisables consistency checking. It is not a routine fix for a warning. Stop, back up and understand the layout first.--wipeand--wipe-partitionscan erase signatures. Leave their defaults alone unless you have deliberately planned that data loss.
Made a mistake in the disposable image? Discard it and start again, that is the whole point of using one. On a real disk there is no universal undo: restore a verified dump or binary table backup only after stopping services, unmounting affected filesystems and confirming the exact target.
Done means
- You checked the installed sfdisk version and target path.
- You dry-ran the script and reviewed its label, sizes and partition count.
- You applied it only to a disposable image, then listed and verified the table.
- You saved a dump before treating the layout as recoverable.
- You know which omitted values sfdisk chooses for you and which options can erase signatures.