← All AI Scripts Boot media · bash

isotousb.sh

Writes an ISO to a USB stick the way Etcher does: raw byte copy, forced flush, and a read-back that proves the bytes actually landed. With the safety rails that are missing when you run dd by hand.

Free to use Linux + bash dd / WoeUSB Verifies the write

This script erases an entire disk. That is the whole point of it, and there is no undo. The safety rails below are built to make picking the wrong disk hard, but read the file before you run it, exactly as with anything else you download and hand root access to.

The problem it solves

dd does the job perfectly well. The problem is everything dd does not do: it will not warn you that /dev/sda is your system disk, it will not tell you the write came out incomplete, and it exits the moment the kernel has accepted the data, not the moment the stick has finished writing it. One wrong letter in the device name and you have overwritten the wrong disk without a single question along the way.

The script adds four things on top: only USB disks appear in the list, you must type the disk size to confirm, the data is forced physically out to the stick, and finally it is read back and compared against the source.

Usage

Must run as root, since it writes to a raw block device.

sudo ./isotousb.sh file.isoNormal run. Detects the ISO type itself.
sudo ./isotousb.shWithout a filename: prompts for the path to the ISO.
--linuxForce a raw dd copy, skipping detection.
--windowsForce the Windows method via WoeUSB.
--autoAutomatic detection. This is the default.
-hHelp text. Does not require root.

Step 1: the script inspects the ISO

Before anything is chosen, the ISO is read. Here with a Debian netinst ISO:

sudo ./isotousb.sh debian-13.6.0-amd64-netinst.iso
$ sudo ./isotousb.sh debian-13.6.0-amd64-netinst.iso

==> Image: debian-13.6.0-amd64-netinst.iso  (755MB)
OK  Secure Boot: ISO ships a signed shim, should boot with Secure Boot ON.
OK  ISO type: Linux / hybrid, correct method is a raw byte-for-byte write (dd).
   Verify manually if you like:
     list files : 7z l -- "debian-13.6.0-amd64-netinst.iso"
     hybrid MBR : dd if="debian-13.6.0-amd64-netinst.iso" bs=512 count=1 2>/dev/null | tail -c2 | xxd
     (55aa in the last 2 bytes = hybrid/dd-writable)
   (If this is wrong, re-run with --linux or --windows to force it.)

Two things have been established here, and you can check both yourself with the commands it prints. The hybrid check reads the last two bytes of sector 0 and looks for the signature 55aa. If it is there, the ISO is built to be copied raw to a disk and still boot:

verifying by hand
$ dd if=debian-13.6.0-amd64-netinst.iso bs=512 count=1 2>/dev/null | tail -c2 | xxd
00000000: 55aa                                     U.

The Secure Boot check looks for a signed boot chain inside the ISO: both bootx64.efi and a grubx64.efi beside it. If both are present you can leave Secure Boot enabled in firmware:

verifying by hand
$ 7z l -- debian-13.6.0-amd64-netinst.iso | grep -iE 'EFI/boot/(boot|grub)x64'
2026-07-11 16:45:08 .....      1036152      1036152  EFI/boot/bootx64.efi
2026-07-11 16:45:08 .....      2684352      2684352  EFI/boot/grubx64.efi

The script cannot add Secure Boot support. That support lives inside the ISO, in the form of a signed shim, and cannot be bolted on from outside. What the script does is tell you whether it is there, so you know in advance whether you need to disable Secure Boot in firmware to get the stick to boot.

Step 2: only USB disks are listed

This is the most important safety rail. The list is built from lsblk, filtered to whole disks that are either flagged removable or sit on the USB transport. The system disk is never offered as an option. On the machine below there are two NVMe disks of nearly a terabyte each, and neither appears:

disk selection
==> Scanning for removable / USB disks...

Available target disks:
  [0]  /dev/sdb        28.9G  Kingston DataTraveler (usb)
      /dev/sdb1  28.9G  vfat   KINGSTON  /media/youruser/KINGSTON

Select target disk number [0-0]: _

The partitions under each disk are shown with label and mount point, so you recognise your stick by its contents rather than by a device name alone. For contrast, lsblk sees every disk in the machine. The filter is what keeps the system disks out:

what the filter does
$ lsblk -dnp -o NAME,SIZE,RM,TRAN,TYPE
/dev/sda         0B  1 usb    disk   ← removable, included in the list
/dev/sdb         0B  1 usb    disk   ← removable, included in the list
/dev/nvme0n1 953.9G  0 nvme   disk   ← system disk, filtered out
/dev/nvme1n1 953.9G  0 nvme   disk   ← system disk, filtered out

Step 3: the confirmation you cannot click past

No [y/N]. You have to type the disk size exactly as shown, which requires actually reading what is in front of you:

confirmation
################  DESTRUCTIVE  ################
About to ERASE and overwrite:
   Disk : /dev/sdb  28.9G  (Kingston DataTraveler)
   With : debian-13.6.0-amd64-netinst.iso
Everything on /dev/sdb will be permanently lost.

To confirm, type the disk size exactly as shown (28.9G): _

Type anything else and the whole thing aborts without a single byte written. On top of that, the script refuses to run if the ISO is stored on the disk you are about to overwrite, since the source would be eaten mid-copy.

Step 4: write, flush and verify

writing
==> Unmounting any partitions on /dev/sdb...
==> Writing image (raw, byte-for-byte) to /dev/sdb...
   Tip: dd holds output until the first block completes, then updates every second.
791674880 bytes (792 MB, 755 MiB) copied, 41 s, 19.3 MB/s
==> Flushing remaining buffers to the device (do NOT unplug)... done.
OK  Write complete.
==> Verifying: reading back 755MB from /dev/sdb and comparing...
   reading the stick back (this is the slow part, pv shows real progress):
 755MiB 0:00:38 [19.7MiB/s] [=========================>] 100%
OK  Verification PASSED, device matches the image byte-for-byte.
OK  Ejected /dev/sdb, safe to remove.

This ISO supports Secure Boot, you can leave Secure Boot ON in firmware.

Verification is the part plain dd skips, and it is the reason Etcher is trustworthy. The first 755 MB are read back off the stick and compared byte for byte against the ISO file. This is how you catch a USB stick that is failing, or a counterfeit one pretending to be bigger than it is. The cache is dropped first, so what gets read comes from the stick and not from RAM.

Why dd status=progress and not pv | dd? Because a pipe measures how fast data reaches the kernel's write cache, which is to say RAM. You get a progress bar that races to 100% and then sits perfectly still while the stick actually writes, and you have no idea whether it has hung or is simply working. dd with conv=fsync exits only once the data is on physical media, so the number you see is real. pv is used during the read-back instead, where reading is genuine progress.

Windows ISOs

A Windows installer ISO cannot simply be copied raw. It needs a partitioned stick with the files laid out on a FAT or NTFS volume. The script recognises a Windows ISO by bootmgr and sources/install.wim in the file listing, and hands the job to WoeUSB-ng, the established open-source tool for exactly this. If install.wim is over 4 GB, NTFS is chosen automatically, since FAT32 cannot hold a file that large.

If WoeUSB is missing, the script prints the exact install commands for your distribution and lets you choose: let it install for you, do it manually in another window and come back, or abort.

Missing tools

At startup it checks what is present on the machine. If something is missing you get the command for your own package manager (apt, dnf, pacman and zypper are known) and the same choice as above. pv and eject are optional: everything works without them, you just get no progress bar during verification.

missing tools
!!  Missing optional tools: pv

   To install, run these commands:

     sudo apt-get update
     sudo apt-get install -y pv

   Options:
     [A] Auto-install now (this script runs it for you)
     [M] I will run it myself, then come back
     [S] Skip (continue without them)
   Choose [A/M/S]: _

Not maintained, change it yourself

Built for my own machine and published as-is. No updates, no support, no guarantees, least of all for a script that erases disks.

If it should do something else, download it and hand the whole file to an AI along with what you want: "skip the verification", "write to two sticks in sequence", "make an ISO from a stick instead". The comments explain why each safety rail is there, so the model, and you, can see what is safe to change and what is there for a reason.