A modern command shell for UEFI firmware: files, disks, boot entries, UEFI variables,
drivers, hardware and network, with a real scripting language built in.
The alphabetical index at the end lists every command, function and topic.
Press / to search.
Introduction
NESH is a shell that runs inside the UEFI firmware, before any operating system starts.
It does what the classic UEFI Shell does, and it is designed to be pleasant to use and easy to script.
What NESH is
Every modern PC starts with UEFI firmware. Before Windows or Linux is loaded, the firmware can run
UEFI applications: boot loaders, setup tools, firmware updaters, diagnostics. A shell is a
UEFI application that gives you a command prompt in that environment, so you can look at disks and files,
change boot entries, read hardware information and run other tools.
NESH is such a shell. It is a single file, nesh.efi, that you start from the firmware boot menu
or from a USB stick. It offers:
>_
A friendly prompt
Line editing, history with search, Tab completion, aliases, colors and clear error messages.
bootmgr lists, adds, orders and checks boot entries, with dry run, confirmation and automatic backups.
≡
UEFI Shell commands
The UEFI Shell command set, rewritten from scratch; their options are accepted too.
{ }
Script-friendly output
With -data, commands print key=value records that scripts read with two functions.
☍
Hardware and network
PCI, SMBIOS, ACPI, memory map, CPU; IPv4 and IPv6, ping, TFTP and HTTP downloads.
NESH and the UEFI Shell
The UEFI Shell (from the EDK2 project) is the standard shell of UEFI. NESH keeps what people already know —
the same command names, the same options, the same fs0: volume names, the same environment
variables — and changes what is hard to use.
Topic
UEFI Shell
NESH
Scripts
.nsh batch files: if, for, goto, %1
.nsb scripts in NESH BASIC: variables, expressions, SUB/FUNCTION, arrays, strings
Using command output in scripts
-sfo (comma separated, hard to read)
-data (key=value) + RECORDS / FIELD$; RUN$() captures any output
history search, word movement, completion, aliases, multi-line BASIC
Network
ifconfig, ping, tftp, http (separate IPv6 tools)
same commands; ping, tftp, http accept IPv4 and IPv6 addresses
Distribution
shell + separate command libraries
one file, nesh.efi — easy to copy and to sign for Secure Boot
Secure Boot
no special handling
low-level hardware writes are disabled while Secure Boot is active
UEFI applications written for the UEFI Shell (the ones using the EDK2 ShellLib) run unchanged under NESH,
because NESH provides the same programming interface. See Running EFI applications and
Differences from the UEFI Shell.
Conventions used in this manual
You see
It means
ls -l
Something you type, a command, a file name or a value.
cp SRC DST
Words in capitals are placeholders: replace them with real values.
[-r]
Square brackets in a syntax line mark something optional.
a | b
A vertical bar in a syntax line means “one of these”.
Ctrl+R
Keys to press.
Examples labeled Console show a session at the prompt: the text up to > is the prompt,
the rest of that line is what you type, and the lines below are the output. Examples labeled
NESH BASIC are script files.
fs0:\> echo Hello
Hello
Tip
Every command explains itself: help lists the commands and help NAME shows the details of one.
help NAME also works for a statement or a function of the scripting language (help PRINT,
help LEN), and help basic and help functions are the two quick references.
The command texts form the command reference at the end of this manual.
Getting started
This chapter shows how to get nesh.efi, how to start it and what to do first.
Requirements
A computer (or virtual machine) with UEFI firmware on the x86-64 architecture.
Almost every PC made after 2012 qualifies.
A FAT-formatted volume the firmware can read: a USB stick, or the EFI System Partition (ESP) of a disk.
To build NESH yourself: a Linux system with gcc, GNU ld, make and python3
(see the developer manual).
Building nesh.efi
$ make
$ ls -l build/nesh.efi
make produces build/nesh.efi, the complete shell in one file. make test runs the
automatic tests; make qemu starts NESH in a virtual machine (QEMU with OVMF firmware), which is the easiest
way to try it without touching a real computer.
Putting NESH on a USB stick
There are two common layouts. Both need a FAT32 (or FAT16) partition.
As the default loader of a removable disk. Copy nesh.efi to
\EFI\BOOT\BOOTX64.EFI on the stick. The firmware boot menu then shows the stick as a boot device,
and choosing it starts NESH directly.
As a tool next to other loaders. Copy nesh.efi to any folder, for example
\EFI\tools\nesh.efi, and start it from another shell or add a boot entry for it
(see below).
Note
NESH treats the volume it was started from as its boot volume. It looks there for the start-up script
startup.nsb, keeps the command history in \nesh_history.txt and puts boot-entry backups in
\nesh\backup. If the volume is read-only, NESH simply works without these files.
Starting NESH
Choose the USB stick (or the NESH boot entry) in the firmware boot menu — usually opened with F12,
F11, F8 or Esc during power-on, depending on the manufacturer. NESH starts with a short
banner and a prompt showing the current directory:
NESH 0.2.0 - New EFI Shell (UEFI x86_64)
Type 'help' for the commands, 'help basic' for the scripting language.
fs0:\>
If Secure Boot is active, the banner has one more line: Secure Boot is active: low-level hardware writes are
disabled. (see Secure Boot).
NESH can also be started from another UEFI shell, with optional arguments:
Command line
Effect
nesh.efi
Interactive shell; runs startup.nsb first if it exists.
nesh.efi -n
Interactive shell, without running startup.nsb.
nesh.efi SCRIPT [ARGS...]
Runs a script and exits with its exit code.
nesh.efi -c "CODE"
Runs one line of BASIC and exits, e.g. nesh.efi -c "PRINT 6*7".
The start-up script
If the boot volume contains \startup.nsb, NESH runs it when it starts. Before that it counts down
three seconds:
Running fs0:\startup.nsb in 3 s (ESC to skip, any other key to start now)
Press Esc to skip the script, or any other key to run it at once. startup.nsb is an ordinary
NESH BASIC script; a typical use is the interactive boot menu.
First steps: a short tour
Try these commands in order. They are safe: none of them changes anything.
fs0:\> map
fs0:\> ls
fs0:\> ver
fs0:\> sysinfo
fs0:\> bootmgr
fs0:\> help
map lists the volumes (fs0:, fs1:…) and the raw block devices (blk0…).
ls lists the files of the current directory; fs1: alone switches to another volume.
ver and sysinfo describe NESH, the firmware and the machine.
bootmgr shows the boot entries, in boot order.
help lists every command; help basic summarizes the scripting language.
To leave NESH type exit: the firmware continues with its boot order, or shows its boot menu.
Using the command line
How to type commands, how NESH reads them, and the tools that make the prompt fast to use.
The prompt and command syntax
The prompt shows the current directory, for example fs0:\efi\boot>. A command line is a command
name followed by words separated by spaces:
fs0:\> cp -r fs0:\efi fs1:\backup
Names are not case-sensitive: LS, ls and Ls are the same command,
and file names are not case-sensitive either (FAT file systems ignore case).
Options start with - and may be combined when they are single letters
(ls -lr). Most commands accept options anywhere on the line; -- ends the options.
Double quotes group words: mkdir "My Files" creates one folder. Inside quotes, two
double quotes "" stand for one double quote character.
Volumes, paths and wildcards
Each file system the firmware can read gets a volume name: fs0:, fs1: and so on. A full path
starts with a volume name, and folders are separated by a backslash. The forward slash works too.
Path
Meaning
fs1:\efi\boot\bootx64.efi
Full path on volume fs1:.
\efi\boot
From the root of the current volume.
boot\grub.cfg
Relative to the current directory.
...
The parent directory, the current directory.
fs1:
Typed alone as a command: switch to volume fs1:.
Wildcards select several files: * matches any text and ? one character.
cp *.efi fs1:\tools copies every .efi file of the current folder. Commands expand wildcards
themselves; the help of each command says whether it accepts them.
Volumes can get extra names with map: after map usb fs1:, the path usb:\data
means fs1:\data. See Volumes and disks.
Line editing, history and completion
Keys
Action
←→Ctrl+BCtrl+F
Move one character.
Ctrl+←Ctrl+→Alt+BAlt+F
Move one word.
HomeEndCtrl+ACtrl+E
Start / end of the line.
BackspaceDel
Delete before / under the cursor.
Ctrl+KCtrl+U
Delete to the end / to the start of the line.
Ctrl+W
Delete the word before the cursor.
Esc
Clear the line.
↑↓
Previous / next command of the history.
Ctrl+R
Search the history: type part of a command; Ctrl+R again finds older
matches; Enter or an arrow key accepts, Esc cancels.
Tab
Complete a command name, an alias or a path. If several completions are possible,
the common part is completed and the choices are listed.
Ctrl+L
Clear the screen.
Ctrl+C
Cancel the line; while a command or script runs, stop it.
The history keeps the last 500 commands and is saved in \nesh_history.txt on the boot volume, so it
survives a restart. history shows it, history 20 the last 20 lines, history -c clears it.
Saving output to a file
> FILE at the end of a command writes its output to a file instead of the screen; >> FILE
appends to the file.
Error messages still appear on the screen. There are no pipes (|): to process the output of a command,
use a script with RUN$() (see Running commands from a script) or save it to a
file and use grep, head or tail.
Note
NESH does not replace %name% in command lines (that is a UEFI Shell script feature): the second example
above writes the text %date% literally. In NESH, use a BASIC expression instead:
RUN "echo checked on " + DATE$ + " >> fs1:\log.txt".
Exit codes
Every command ends with an exit code: 0 means success, any other value an error. Scripts read it in
ERR; at the prompt it is kept in the read-only environment variable lasterror.
Code
Meaning
0
Success.
1
The command failed (file not found, device error…). Some commands use 1 for “no”:
grep when nothing matched, comp when files differ.
2
Wrong usage: unknown option, missing argument.
127
Command not found.
130
Stopped with Ctrl+C.
other
EFI applications and scripts may return any code (a script with END 5 returns 5).
Running scripts and EFI programs
Scripts (.nsb) and UEFI applications (.efi) run like commands: type their name, with or without
the extension, followed by their arguments.
A name without a folder is searched in the directories listed in the environment variable path
(separated by ;, where . is the current directory). By default path is
.;fsN:\efi\tools;fsN:\efi\boot;fsN:\, where fsN: is the boot volume. For each directory NESH tries
NAME.nsb, then NAME.efi, then NAME itself. which NAME tells what a name
refers to.
A file without one of those two extensions is run only when it really is a UEFI application for this
machine: NESH reads its headers and asks for the MZ and PE signatures, x86-64 code and an
application (not a driver). This is what makes vmlinuz — a Linux kernel with the EFI stub, which nobody
names vmlinuz.efi — start by typing its name, while a data file such as live.img answers
command not found. A script must end in .nsb: there is no signature to recognise it by.
Environment variables
Environment variables are named text values shared by the shell and the programs it starts.
They are the same as in the UEFI Shell.
fs0:\> set -v target fs1:\backup
fs0:\> set target
fs1:\backup
fs0:\> set -d target
set NAME VALUE creates a permanent variable, kept in the firmware (NVRAM) across reboots.
set -v NAME VALUE creates a temporary one, lost when NESH exits.
Permanent variables are stored exactly like the UEFI Shell stores them, so both shells see the same values.
pager: set it to off to stop the automatic paging of long output.
Some variables are computed by NESH and read-only: cwd, lasterror, uefiversion,
uefishellversion, uefishellsupport, neshversion.
Scripts read and write them with ENV$, SETENV and DELENV. They are separate
from BASIC variables: a script variable called path$ does not change path.
Aliases
An alias is a short name for a command with its options:
fs0:\> alias ll ls -l
fs0:\> ll fs1:\efi
The second line runs ls -l fs1:\efi: the extra words are added at the end. Like variables, aliases are
permanent unless created with alias -v, and alias -d NAME deletes one. NESH defines a few
temporary aliases for names used by other shells: copy (cp), ren and move (mv),
rd (rmdir).
BASIC at the prompt
Lines that are BASIC statements run directly at the prompt, which makes NESH a handy calculator and a place to try
script fragments. A line is treated as BASIC when it starts with a statement keyword (PRINT, FOR,
IF, DIM…), assigns a variable (x = 5) or calls a SUB you defined. Everything else is a
command.
fs0:\> PRINT HEX$(&HFF * 16)
FF0
fs0:\> n = 0
fs0:\> FOR i = 1 TO 5
... n = n + i
... NEXT
fs0:\> PRINT n
15
When a block (FOR, IF, SUB…) is not finished, the prompt becomes ...
until it is; Ctrl+C cancels the block. Variables and SUBs defined at the prompt stay available
until NESH exits.
Long output: paging
A UEFI console cannot be scrolled back, so output that does not fit would be lost. When you type a command at the
prompt and its output goes to the screen, NESH stops at every screenful:
fs0:\> help
acpiview List the ACPI tables, or show or save one
...
-- More -- (Enter: one line, Space: one page, q: stop)
Key
Does
Space
Show the next screenful.
Enter
Show one more line.
q (or Esc, Ctrl+C)
Stop: the command ends and the prompt comes back.
Paging never gets in the way of automation: it is off inside scripts and whenever the output is redirected to a file
or captured with RUN$. Two ways to control it:
Command
Effect
set pager off
No automatic paging at the prompt (set -d pager or set pager on restores it).
COMMAND -b
Page this command even inside a script; the option of the UEFI Shell.
more FILE...
Print files one screen at a time (like cat, always paged).
To keep a long output instead, save it to a file: dh > fs1:\handles.txt.
Stopping a command
Ctrl+C stops the running command, script or listing (exit code 130).
Working with files and folders
Listing, copying, moving and deleting files; attributes; comparing files.
The commands work on any volume the firmware can read, and write where the volume is writable.
Listing files
ls shows names; ls -l (or dir) adds date, time, attributes and size.
Directory names end with \.
Copies files; -r copies folders with their contents. Existing files are overwritten
without asking. If a copy fails or is stopped, the partial file is removed.
mv SRC... DST
Moves or renames. An existing target file is replaced only after the move has succeeded.
Between volumes it copies, then deletes the source only after a complete copy.
rm [-r] [-f] PATH...
Deletes files; -r also folders. Nothing is asked. -f: no error when
nothing matches. Read-only files must be unlocked first with attrib -r.
mkdir [-p] DIR...
Creates folders; -p creates the whole path.
rmdir DIR...
Removes empty folders.
touch FILE...
Creates empty files or updates their time.
setsize SIZE FILE...
Truncates or extends files to an exact size.
Be careful
Like the UEFI Shell, NESH does not ask for confirmation before overwriting or deleting, and there is no recycle bin.
Double-check wildcards: ls PATTERN first shows exactly what rm PATTERN would delete.
Attributes
FAT files have four attributes: read-only, hidden, system and
archive. attrib shows and changes them:
comp lists the differences between two files (offsets in hex, bytes of both files); cmp stops at the
first one. Both end with ERR = 0 when the files are identical, which makes them useful in scripts:
RUN "cmp", "fs0:\efi\boot\bootx64.efi", "fs1:\backup\bootx64.efi"
IF ERR = 0 THEN PRINT "The backup is up to date" ELSE PRINT "The loader has changed"
Volumes and disks
How NESH names disks and file systems, and how to inspect them at a low level.
Volumes and block devices: map
The firmware exposes two kinds of storage objects. Volumes (fs0:, fs1:…) are file systems
NESH can read and write files on. Block devices (blk0, blk1…) are raw disks, partitions and
drives, including those with no file system the firmware understands (for example an NTFS or ext4 partition).
fs0:\> map
Volume Label Size Free Flags
fs0 QEMU VVFAT 503.7M 502.9M ro boot
fs1 NESHWORK 31.9M 31.9M
Device Type Size Volume
blk0 removable - (no media)
blk1 disk 504M
blk2 partition 503M fs0
blk3 disk 32M fs1
The flags say ro (read-only), removable and boot (the volume NESH started from).
map -v adds the device path of each entry, the firmware's full description of where the device is.
Volume numbers depend on the order in which the firmware found the devices, so fs1: today may be
fs2: after plugging in another stick. Two ways to be independent of the numbering:
Give the volume an extra name for this session: map usb fs1:, then use usb:\file.
map -d usb removes the name.
In scripts, find the volume by its label with map -data and FIELD$
(see Script-friendly output).
After connecting a device, map -r rescans the devices.
Labels and free space: vol
fs0:\> vol
Volume fs0: QEMU VVFAT (ro)
528171008 bytes total disk space
527351808 bytes available on disk
fs0:\> vol fs1: -n BACKUP
Raw blocks: dblk and hexedit
dblk DEVICE LBA COUNT shows raw disk blocks in hex and recognizes MBR partition tables, GPT headers and
FAT boot sectors. hexedit -d DEVICE LBA COUNT opens blocks in the hex editor. Numbers are hexadecimal.
fs0:\> dblk blk1 0 1
Be careful
Writing raw blocks with hexedit -d bypasses the file system: a wrong byte in a partition table or boot
sector can make a disk unbootable. Save a copy of the blocks you change first.
Text, time and data tools
Reading and searching text files, dumps, date and time. Text commands read UTF-8 and UCS-2
(“Unicode”) files and ignore Windows line ends.
Command
Use
Example
cat / type
Print files.
cat fs0:\efi\boot\grub.cfg
head / tail
First / last lines.
tail -n 20 log.txt
grep
Lines containing a text; -i any case, -n line numbers, -c count, -v non-matching.
grep -in timeout *.cfg
wc
Count lines, words and bytes.
wc notes.txt
hexdump
Hex dump of a file.
hexdump -n 64 nesh.efi
date / time
Show or set the clock.
date 2026-09-19
timezone
Time zone of the real-time clock.
timezone -s +01:00
sleep / stall
Wait: sleep in milliseconds (Ctrl+C stops it), stall in microseconds.
sleep 500
eficompress / efidecompress
UEFI compression format, as used in option ROMs and firmware volumes.
Two full-screen editors are built in: edit for text files and hexedit for
binary files, disk blocks and memory.
edit — text editor
edit FILE opens a file (or a new one, created when you save). Arrow keys, Home/End,
PgUp/PgDn move around; typing inserts text. The function keys have Ctrl equivalents for
terminals where function keys do not work (serial consoles):
Key
Or
Action
Key
Or
Action
F1
Ctrl+G
Go to line
F6
Ctrl+K
Cut the current line
F2
Ctrl+S
Save
F7
Ctrl+U
Paste the cut lines
F3
Ctrl+Q
Exit (also Esc)
F8
Ctrl+O
Open another file
F4
Ctrl+F
Find
F9
Ctrl+T
Switch UTF-8 / UCS-2
F5
Ctrl+R
Find and replace
F10
Ctrl+N
Find next
Several cuts in a row form one block, and paste inserts the last block: to move lines, cut them one after the other,
move the cursor and paste. Ctrl+E shows the key list inside the editor. The file keeps its
encoding, its line ends (LF or CRLF), a UTF-8 byte-order mark if it had one, and its tab characters.
hexedit — binary editor
Command
Edits
hexedit FILE
A file.
hexedit -d DEVICE LBA COUNT
Disk blocks (DEVICE: blkN, fsN: or a handle).
hexedit -m ADDRESS SIZE
Memory (writing is disabled while Secure Boot is active).
Arrow keys and PgUp/PgDn move, Tab switches between the hex and the text column,
F1 goes to an offset, F2 saves, F3 exits.
Scripting with NESH BASIC
NESH scripts are written in NESH BASIC, a small and readable language in the tradition of
BASIC: variables, loops, functions, strings and arrays, plus direct access to shell commands and firmware data.
This chapter is a complete guide, from the first script to the full function reference.
Your first script
A script is a text file with the extension .nsb. Create it with edit hello.nsb (or on another
computer) and run it by typing its name:
' hello.nsb - my first script
PRINT "Hello from NESH "; VERSION$
name$ = "world"
PRINT "Hello, " + name$ + "!"
fs0:\> hello
Hello from NESH 0.2.0
Hello, world!
A line starting with ' (or REM) is a comment.
PRINT writes text; ; between items joins them without spaces.
name$ is a variable. Names ending with $ hold text; the others hold numbers.
+ joins strings.
Keywords and names are not case-sensitive: print, PRINT and Print are the same.
This manual writes keywords in capitals to make them stand out.
Lines, statements and comments
Rule
Example
One statement per line, or several separated by :
a = 1 : b = 2
A long line continues on the next one when it ends with a space and _
IF a = 1 AND _
Comments start with ' or REM and run to the end of the line
x = 5 ' five
Strings are in double quotes; "" inside a string is one quote
"say ""hi"""
Files are UTF-8 (a byte-order mark is allowed) or UCS-2; #! on the first line is ignored
Variables, numbers and strings
There are two types, chosen by the name:
Numbers: 64-bit integers, from about −9.2·1018 to 9.2·1018. There are no
fractions: 7 / 2 is 3. Literals can be written in decimal, hexadecimal
(&HFF or 0xFF), binary (&B1010 or 0b1010) or octal
(&O17); _ may separate digits (0xFFFF_0000).
Strings: names ending in $. Any length, UTF-8 text.
Variables need no declaration: an unused number variable is 0 and an unused string is "".
Assigning a string to a number variable (or the reverse) is an error; convert with STR$ and VAL.
count = 42 ' a number (64-bit integer)
size = &H1000 ' hexadecimal: 4096
mask = 0b1010 ' binary: 10
label$ = "EFI System" ' a string: the name ends with $
PRINT count, size, mask
PRINT label$; " has "; LEN(label$); " characters"
PRINT 7 / 2, 7 MOD 2, 2 ^ 10, -7 \ 2
PRINT "a" < "b", 3 > 5
fs0:\> vars
42 4096 10
EFI System has 10 characters
3 1 1024 -3
-1 0
Note
Unlike classic BASIC, PRINT adds no spaces around numbers: PRINT "has"; 10 prints
has10. Put the spaces in the strings. A comma moves to the next 14-column zone, which is handy for simple tables.
Operators
Priority
Operators
Meaning
1 (first)
^
Power (right to left: 2^3^2 = 29)
2
-x+x
Sign
3
*/\MOD
Multiply; divide (both / and \ are integer divisions, rounding toward zero); remainder
4
+-
Add, subtract; + also joins strings
5
SHLSHR
Shift bits left / right (1 SHL 4 = 16)
6
=<><><=>=
Comparisons (numbers or strings)
7
NOT
Bitwise not
8
AND
Bitwise and
9 (last)
ORXOR
Bitwise or, exclusive or
A comparison gives -1 when true and 0 when false, as in classic BASIC; any non-zero number
(or non-empty string) counts as true in IF and loops. Because true is -1 (all bits set),
AND, OR and NOT work both on bits and on conditions. Both sides of AND/OR
are always evaluated. Strings compare byte by byte, so the comparison is case-sensitive: use UCASE$ on
both sides to ignore case.
Output and input
Statement
Effect
PRINT a; b$, c
Prints values; ; joins, , moves to the next 14-column zone.
A final ; or , keeps the cursor on the line.
INPUT "Name: "; n$
Asks for a line of text (or a number, for a number variable: it asks
again until one is typed). Ctrl+C stops the script.
IF free < 1000000 THEN PRINT "almost full" ELSE PRINT "ok"
IF ERR = 0 THEN
PRINT "done"
ELSEIF ERR = 127 THEN
PRINT "command not found"
ELSE
PRINT "failed with code "; ERR
END IF
Loops: FOR counts, WHILE repeats while a condition holds, DO … LOOP tests at the start
or at the end (WHILE or UNTIL):
FOR i = 1 TO 3
IF i = 2 THEN
PRINT i; " is two"
ELSE
PRINT i
END IF
NEXT
n = 10
WHILE n > 1
IF n MOD 2 = 0 THEN n = n / 2 ELSE n = 3 * n + 1
PRINT n;
IF n > 1 THEN PRINT " ";
WEND
PRINT
DO
tries = tries + 1
LOOP UNTIL tries = 3
PRINT "tries:"; tries
FOR i = 10 TO 0 STEP -5: PRINT i;: NEXT: PRINT
fs0:\> control
1
2 is two
3
5 16 8 4 2 1
tries:3
1050
EXIT FOR, EXIT WHILE, EXIT DO leave a loop; CONTINUE FOR (WHILE, DO)
skips to the next round.
WHILE … END WHILE is accepted as well as WEND. NEXT i may repeat the variable name.
A loop checks for Ctrl+C, so an endless loop can always be stopped.
SELECT CASE compares one value against lists, ranges (TO) and conditions (IS):
FOR code = 0 TO 4
SELECT CASE code
CASE 0
msg$ = "success"
CASE 1, 2
msg$ = "failed"
CASE 3 TO 9
msg$ = "unusual"
END SELECT
PRINT code; ": "; msg$
NEXT
SELECT CASE "fs1:"
CASE IS < "fs1:"
PRINT "before"
CASE ELSE
PRINT "fs1: or later"
END SELECT
fs0:\> select
0: success
1: failed
2: failed
3: unusual
4: unusual
fs1: or later
GOTO jumps to a label, a name followed by :alone on its line. It can jump within the
same block or out of loops, not into them. Structured statements are usually clearer.
i = 0
again:
i = i + 1
IF i < 3 THEN GOTO again
PRINT "i ="; i
fs0:\> gotolabels
i =3
Arrays
DIM name(N) creates an array with the elements 0 to N (so N+1 elements); string arrays
end with $. Arrays have one dimension. REDIM changes the size and keeps the values;
UBOUND gives the last index. Functions that take a whole array use the name with empty parentheses,
like disk$().
DIM disk$(2) ' three elements: 0, 1 and 2
disk$(0) = "fs0:"
disk$(1) = "fs1:"
disk$(2) = "fs2:"
PRINT UBOUND(disk$()); " is the last index"
PRINT JOIN$(disk$(), ", ")
n = SPLIT("ata;nvme;usb", ";", bus$())
FOR i = 0 TO n - 1
PRINT i; "="; bus$(i)
NEXT
REDIM disk$(3) ' grow, keeping the values
disk$(3) = "fs3:"
PRINT JOIN$(disk$(), " ")
fs0:\> arrays
2 is the last index
fs0:, fs1:, fs2:
0=ata
1=nvme
2=usb
fs0: fs1: fs2: fs3:
SPLIT and RECORDS create or resize the array they fill, so it needs no DIM.
SUB and FUNCTION
A SUB is a named block of statements; a FUNCTION also returns a value with RETURN
(a function whose name ends with $ returns a string). They can be defined anywhere in the script at the top
level, also after the lines that use them.
FUNCTION human$(bytes)
' 1536 -> "1 KiB"
LOCAL i, u$(4)
i = SPLIT("B KiB MiB GiB TiB", " ", u$())
i = 0
WHILE bytes >= 1024 AND i < 4
bytes = bytes \ 1024
i = i + 1
WEND
RETURN STR$(bytes) + " " + u$(i)
END FUNCTION
SUB banner(title$)
PRINT STRING$(LEN(title$) + 4, "=")
PRINT "= "; title$; " ="
PRINT STRING$(LEN(title$) + 4, "=")
END SUB
banner "Disk sizes"
PRINT human$(512)
PRINT human$(1536)
PRINT human$(250059350016)
fs0:\> procs
==============
= Disk sizes =
==============
512 B
1 KiB
232 GiB
Call a SUB with its name followed by the arguments (banner "Title") or with
CALL banner("Title"). A function is used inside an expression, with parentheses.
Parameters receive copies of the values: changing bytes inside human$ does not change the
caller's variable. A parameter is a number or a string according to its name.
Variables are global unless declared with LOCAL inside the SUB or FUNCTION.
LOCAL can also create local arrays (LOCAL u$(4)). A DIM inside a procedure creates a
global array, which a second call cannot DIM again.
RETURN without a value (or EXIT SUB, EXIT FUNCTION) leaves early. A function that ends
without RETURN returns 0 or "".
Procedures may call themselves (recursion), up to 200 levels deep.
Names of built-in functions cannot be used for variables, arrays, parameters or procedures.
Running commands from a script
Scripts run shell commands with RUN, capture their output with RUN$() and check the result
in ERR:
RUN "mkdir -p backup"
PRINT "mkdir: ERR="; ERR
RUN "cp", "hello.nsb", "backup\hello copy.nsb"
out$ = RUN$("ls backup")
PRINT "backup contains: "; out$
RUN "ls", "nothing-here"
IF ERR <> 0 THEN PRINT "ls failed with code "; ERR
RUN "echo saved by a script" TO "log.txt"
RUN "echo second line" APPEND "log.txt"
PRINT READFILE$("log.txt");
fs0:\> runcmd
mkdir: ERR=0
backup contains: hello copy.nsb
ls: nothing-here: not found
ls failed with code 1
saved by a script
second line
Form
Use
RUN "cmd arg1 arg2"
One string: split like a command line (quotes group words, > file works).
RUN "cmd", a$, b$
Separate arguments, passed exactly as they are — the safe way for
file names with spaces or quotes.
RUN … TO "file" / RUN … APPEND "file"
Output to a file (replace / add).
x$ = RUN$(…)
Same arguments as RUN; returns the output as a string, without the final
newlines. Error messages still go to the screen.
ERR
Exit code of the last command (0 = success).
Scripts and .efi programs are run the same way: RUN "backup fs1:". Each script has its own
variables; values are passed with arguments, files or environment variables.
Arguments and exit code
ARGC is the number of arguments and ARG$(n) the n-th one (ARG$(0) is the script's own path).
END code stops the script and sets its exit code, which the caller sees in ERR.
' args.nsb: prints its arguments
PRINT "script: "; ARG$(0)
PRINT "arguments:"; ARGC
FOR i = 1 TO ARGC
PRINT i; ": "; ARG$(i)
NEXT
IF ARGC = 0 THEN
PRINT "usage: args NAME..."
END 2
END IF
RUN "args one ""two words"""
RUN "args"
PRINT "exit code:"; ERR
fs0:\> callargs
script: fs0:\args.nsb
arguments:2
1: one
2: two words
script: fs0:\args.nsb
arguments:0
usage: args NAME...
exit code:2
To stop…
Use
this script, with an exit code
END 2 (also EXIT 2, or RUN "exit /b 2")
all scripts and leave NESH
RUN "exit 2"
Reading and writing files
WRITEFILE "notes.txt", "first line" + CHR$(10)
APPENDFILE "notes.txt", "second line" + CHR$(10)
PRINT "size:"; FILESIZE("notes.txt")
text$ = READFILE$("notes.txt")
n = SPLIT(TRIM$(text$), CHR$(10), line$())
PRINT n; " lines, the second is: "; line$(1)
IF FILEEXISTS("notes.txt") THEN PRINT "notes.txt exists"
x$ = READFILE$("missing.txt")
PRINT "reading a missing file: ERR="; ERR
f$ = DIR$("*.txt")
WHILE f$ <> ""
PRINT "found "; f$
f$ = DIR$
WEND
fs0:\> files
size:23
2 lines, the second is: second line
notes.txt exists
reading a missing file: ERR=1
found log.txt
found notes.txt
File functions never stop the script: they set ERR (0 success, 1 failure), so the script can react.
READFILE$ reads UTF-8 and UCS-2 text and removes carriage returns; WRITEFILE and
APPENDFILE write UTF-8. DIR$(pattern$) returns the first matching name and each following
DIR$ the next one, then "".
A mistake in the script (a syntax error, a division by zero, an index out of range, a type mismatch) stops it with
a message that names the file and the line; the exit code is 1. A syntax error is reported before anything runs.
PRINT "before"
x = 10
y = 0
PRINT x / y
PRINT "never printed"
fs0:\> errors
before
fs0:\errors.nsb:4: error: division by zero
Command failures are not script errors: RUN sets ERR and the script continues. Check
ERR after the commands that matter. nesh.efi -k SCRIPT checks the syntax of a script without running it.
Menus and keys
MENU(title$, items$ [, timeout [, default]]) shows a menu and returns the number of the chosen item
(counted from 1), or 0 if Esc was pressed. Items are separated by |. The user moves with the arrow
keys and chooses with Enter, or presses the item number. With a timeout (in seconds), the default item is
chosen when time runs out; any key stops the countdown.
choice = MENU("Backup", "Copy the loaders|Copy everything|Cancel", 15, 1)
IF choice = 1 THEN RUN "cp -r fs0:\efi fs1:\backup"
IF choice = 2 THEN RUN "cp -r fs0:\ fs1:\backup"
Backup
1. Copy the loaders
2. Copy everything
3. Cancel
Up/Down + Enter to choose, ESC to cancel. Default in 15 s
A menu usually sits in a loop, so that the program comes back to it after each action; examples\menu.nsb
is a complete one:
DO
choice = MENU("What do you want to do?", _
"Show the system|List the boot entries|Leave the menu")
SELECT CASE choice
CASE 1
RUN "sysinfo"
CASE 2
RUN "bootmgr list"
CASE 0, 3 ' 0 means Esc
END 0
END SELECT
PAUSE "Press a key to go back to the menu..."
LOOP
KEY$ reads single keys: KEY$ returns a key if one is waiting (or ""), KEY$(ms) waits up
to ms milliseconds (−1: forever). Special keys have names: "UP", "DOWN",
"LEFT", "RIGHT", "HOME", "END", "PGUP", "PGDN",
"INSERT", "DELETE", "ENTER", "ESC", "TAB",
"BACKSPACE", "F1"…"F10".
Worked example: an interactive boot menu
This script shows a menu of the boot entries each time the computer starts, with a 10-second countdown, and
starts the chosen system. It is the examples\bootmenu.nsb file shipped with NESH. It uses three things
explained in this manual: -data output read with RECORDS and FIELD$, the MENU
function, and the boot commands.
flowchart TD
A["bootmgr -data<br/>read the boot entries"] --> B{"entry in the boot order,<br/>active, not hidden,<br/>not this shell?"}
B -- yes --> C["add it to the menu"]
B -- no --> D["skip it"]
C --> E["MENU with a 10 s countdown"]
D --> E
E -- "a system" --> F["bootmgr next -B ID<br/>(BootNext: next boot only)"]
F --> G["reset: the firmware starts it"]
E -- "Firmware setup" --> H["reset setup"]
E -- "Power off" --> I["reset -s"]
E -- "Stay / Esc" --> J["NESH prompt"]
How the boot menu works
' bootmenu.nsb - interactive boot menu built from the firmware boot entries.
' Copy it to the root of the boot volume as startup.nsb to show it at every start.
' The entries, from "bootmgr -data": one record per entry, in boot order.
n = RECORDS(RUN$("bootmgr -data"), rec$())
DIM id$(n), desc$(n)
count = 0
items$ = ""
FOR i = 0 TO n - 1
r$ = rec$(i)
' keep the entries that are in the boot order, active, not hidden and
' not the one that started this shell
IF FIELD$(r$, "kind") = "entry" AND FIELD$(r$, "order") <> "-" AND _
FIELD$(r$, "active") = "yes" AND FIELD$(r$, "hidden") = "no" AND _
FIELD$(r$, "current") = "no" THEN
id$(count) = FIELD$(r$, "id")
desc$(count) = FIELD$(r$, "description")
items$ = items$ + desc$(count) + "|"
count = count + 1
END IF
NEXT
items$ = items$ + "Firmware setup|Power off|Stay in the shell"
' 10 seconds to choose; then the first entry starts
choice = MENU("Start which system?", items$, 10, 1)
SELECT CASE choice
CASE 1 TO count
PRINT "Starting "; desc$(choice - 1); "..."
' BootNext: used once at the next boot; -B: no backup for this change
RUN "bootmgr next -B " + id$(choice - 1)
IF ERR = 0 THEN RUN "reset"
PRINT "Cannot set the next boot entry (error "; ERR; ")"
CASE count + 1
RUN "reset setup"
CASE count + 2
RUN "reset -s"
CASE ELSE
PRINT "Staying in the shell."
END SELECT
How it works:
Read the entries.bootmgr -data prints one record for the boot settings and one per boot
entry, in boot order, with fields such as id, description, active and hidden.
RECORDS splits them into the array rec$().
Choose what to show. Entries outside the boot order, disabled, hidden (such as the firmware's own
setup application) and the entry that started NESH are skipped. The IDs and names are kept in two arrays, and the
names are joined with | for MENU.
Ask.MENU returns the chosen number, or the first entry after 10 seconds.
Start the system.bootmgr next ID sets BootNext, a firmware variable that says
“start this entry once, at the next boot”, and reset restarts the machine; the firmware then starts the
chosen entry and afterwards goes back to the normal boot order. The option -B skips the automatic backup
that bootmgr otherwise saves before every change, which would pile up at every start (and fail on a
read-only volume).
To install it, copy the file to the root of the volume NESH starts from with the name
startup.nsb, and make NESH the first boot entry (bootmgr top ID). The menu then appears at every
start; Esc during the three-second countdown before it (or the “Stay in the shell” item) gives you the prompt.
Show only some systems: test FIELD$(r$, "description") with INSTR.
Remember the last choice: write the ID to a file with WRITEFILE and pass its position as the
default item of MENU.
Add your own items, for example a tool on the disk: run it with RUN "fs0:\efi\tools\memtest.efi"
when chosen.
Starting a Linux kernel with different options
A menu does not have to choose between different systems: it can choose between different ways of starting the
same one. Almost every x86-64 distribution ships a kernel built as an EFI application (the “EFI stub”), so
NESH can start vmlinuz itself and give it a command line — exactly what a boot loader does. The kernel
is usually called vmlinuz, without an extension, and NESH runs it as it is. Anything the script writes
after the file name reaches the kernel:
In a script the line is built as a string, so one entry per set of options is all it takes:
kernel$ = "fs0:\vmlinuz"
root$ = "root=/dev/sda2 ro"
choice = MENU("Start Linux", "Normal|Safe graphics|Rescue", 10, 1)
SELECT CASE choice
CASE 1 : opt$ = root$
CASE 2 : opt$ = root$ + " nomodeset"
CASE 3 : opt$ = root$ + " single"
END SELECT
RUN kernel$ + " initrd=initrd.img " + opt$
examples\linuxboot.nsb is the finished version, with a ten-second countdown and an entry that asks for
the options from the keyboard. Two details are worth knowing:
The kernel receives the file name as the first word of its command line (Command line: fs0:\vmlinuz
root=…). This is what the UEFI Shell does as well, and the kernel ignores it.
initrd= is a path on the kernel's own volume, without the fsN: prefix: the
kernel's EFI stub loads the file itself, next to the kernel unless a leading backslash says otherwise.
Kernel or boot entry?
Starting the kernel directly, as above, keeps everything in one script and lets you change the options without
touching the firmware. The other way is to create one firmware boot entry per set of options —
bootmgr add fs0:\vmlinuz "Linux (rescue)" "initrd=initrd.img root=/dev/sda2 ro single" — and let the
menu pick one with bootmgr next ID followed by reset. Use that when other boot menus, or the
firmware itself, must see the entries too.
More examples
The examples folder contains complete scripts:
Script
What it shows
bootmenu.nsb
The interactive boot menu above.
findefi.nsb
Looks for boot loaders in \EFI\*\ on every volume: map -data,
ls -ad -data, DIR$, a SUB with a LOCAL variable.
linuxboot.nsb
One Linux kernel, several sets of options: a countdown menu that builds
the kernel command line, with an entry that asks for the options.
inventory.nsb
Writes a text report of the machine (system, volumes, boot entries, memory)
with RUN$ and APPENDFILE.
menu.nsb
A maintenance menu that comes back after every action, with a second menu built
at run time from the volumes found by map -data.
' findefi.nsb - lists the boot loaders in \EFI\*\ of every volume.
SUB scan(folder$)
LOCAL f$
f$ = DIR$(folder$ + "\*.efi")
WHILE f$ <> ""
PRINT " "; folder$; "\"; f$
f$ = DIR$
WEND
END SUB
nv = RECORDS(RUN$("map -t fs -data"), vol$())
FOR v = 0 TO nv - 1
name$ = FIELD$(vol$(v), "volume") + ":"
IF DIREXISTS(name$ + "\EFI") THEN
PRINT name$; " "; FIELD$(vol$(v), "label")
' the folders inside \EFI (-ad: directories only)
nd = RECORDS(RUN$("ls -ad -data " + name$ + "\EFI"), sub$())
FOR i = 0 TO nd - 1
scan name$ + "\EFI\" + FIELD$(sub$(i), "name")
NEXT
END IF
NEXT
Functions that do something rather than compute a value — SETENV, DELENV, WRITEFILE,
APPENDFILE, SETVAR, SETVARSTR, DELVAR — can also be written as statements,
without parentheses: WRITEFILE "a.txt", text$.
Function reference
Arguments ending in $ are strings, the others numbers. Functions without arguments are written without
parentheses (ERR, TICKS). Positions in strings start at 1.
Strings
LEN(s$)
Number of characters.
LEFT$(s$, n)
The first n characters.
RIGHT$(s$, n)
The last n characters.
MID$(s$, start [, n])
n characters from position start (all the rest without n).
INSTR([start,] s$, find$)
Position of find$ in s$ (from start), 0 if absent. Case-sensitive.
UCASE$(s$) · LCASE$(s$)
Upper / lower case (letters A–Z only).
TRIM$(s$) · LTRIM$(s$) · RTRIM$(s$)
Remove spaces (and tabs, newlines) at both ends / the start / the end.
REPLACE$(s$, find$, new$)
Replace every find$ with new$.
STRING$(n, c$ | code)
n copies of a character: STRING$(3, "*") = "***".
SPACE$(n)
n spaces.
LPAD$(s$, width [, c$]) · RPAD$(s$, width [, c$])
Pad on the left / right to width
characters with spaces (or c$); longer strings are not cut.
CHR$(code)
The character with a Unicode code: CHR$(10) is a newline.
ASC(s$)
Unicode code of the first character.
SPLIT(s$, sep$, arr$())
Split s$ at every sep$ into arr$(); returns the
number of parts. With sep$ = "" it splits at runs of spaces.
JOIN$(arr(), sep$)
Join the elements of an array with sep$ between them.
Numbers and conversions
VAL(s$)
Number in a string: decimal, 0x/&H hex, 0b/&B binary, with an
optional sign; leading spaces are skipped and reading stops at the first invalid character. 0 if none.
Value of key=value in a record; "" and ERR = 1 if missing.
Firmware: UEFI variables and Secure Boot
guid$ is a GUID (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) or one of the names global (the default),
security, shim, shell, systemd. After a firmware error ERR holds the low byte of
the UEFI status code (for example 14 = not found).
VAREXISTS(name$ [, guid$])
True if the variable exists.
VAR$(name$ [, guid$])
Value as text: UCS-2 strings are converted; other data is returned as it is, up to the first
zero byte (use VARHEX$ for binary data).
VARHEX$(name$ [, guid$])
Value as hex bytes, e.g. "0100".
VARNUM(name$ [, guid$])
Value as a little-endian number (e.g. Timeout).
SETVAR name$, hex$ [, guid$ [, attr]]
Write bytes given in hex. Without attr an existing
variable keeps its attributes and a new one is non-volatile with boot and runtime access (7).
SETVARSTR name$, text$ [, guid$ [, attr]]
Write a UCS-2 string (with terminator).
DELVAR name$ [, guid$]
Delete a variable.
FWVENDOR$
Firmware vendor, e.g. "American Megatrends".
SECUREBOOT
True if Secure Boot is active.
Firmware: boot entries
Entries are identified by their number (the #### of Boot####, e.g. &H0003).
BOOTCOUNT
Number of entries in the boot order.
BOOTID(i)
Number of the i-th entry of the boot order (i from 0).
BOOTDESC$(id)
Description; ERR = 127 if the entry does not exist.
BOOTPATH$(id)
Device path, as text.
BOOTARGS$(id)
Optional data (arguments), as text.
BOOTENABLED(id)
True if the entry is active.
BOOTCURRENT
Number of the entry used for this boot, −1 if unknown.
' list the boot order with the descriptions
FOR i = 0 TO BOOTCOUNT - 1
id = BOOTID(i)
PRINT HEX$(id, 4); " "; BOOTDESC$(id)
NEXT
PRINT "Timeout: "; VARNUM("Timeout"); " s, Secure Boot: "; SECUREBOOT
Script-friendly output (-data)
Command output is designed for people: aligned columns, headings, units. Scripts need
something simpler. With the option -data, many commands print their information as records of
key=value lines that a script reads with two functions.
The format
One field per line: key=value. Keys are lower case; the value is the rest of the line.
An empty line separates two records (for example two files, or two volumes).
Yes/no values are yes and no; sizes and counts are decimal numbers; handles and IDs are hexadecimal,
as elsewhere in the shell.
A missing value is an empty field (label=), so the set of keys is the same in every record.
RECORDS(text$, arr$()) splits the output into an array with one record per element and returns the number of
records. FIELD$(record$, key$) returns the value of one field, or "" with ERR = 1 when the
record has no such key.
RUN "mkdir d"
WRITEFILE "d\a.txt", "hello"
WRITEFILE "d\big.bin", STRING$(3000, "x")
n = RECORDS(RUN$("ls -data d"), f$())
FOR i = 0 TO n - 1
PRINT RPAD$(FIELD$(f$(i), "name"), 10); LPAD$(FIELD$(f$(i), "size"), 6); " bytes"
NEXT
A typical use: find a volume by its label instead of its number, which can change.
' returns the volume with the given label, e.g. "fs1:", or "" if none
FUNCTION volume$(label$)
LOCAL n, i, v$(0)
n = RECORDS(RUN$("map -data"), v$())
FOR i = 0 TO n - 1
IF FIELD$(v$(i), "kind") = "volume" AND UCASE$(FIELD$(v$(i), "label")) = UCASE$(label$) THEN
RETURN FIELD$(v$(i), "volume") + ":"
END IF
NEXT
RETURN ""
END FUNCTION
target$ = volume$("BACKUP")
IF target$ = "" THEN
PRINT "Please insert the BACKUP disk"
END 1
END IF
RUN "cp", "-r", "fs0:\efi", target$ + "\efi"
name, media, policy, mac, ip, mask (IPv4), gateway, dns (dad for IPv6)
The exact fields of each command are also listed at the end of its help. Commands without -data
reject the option with an error. The UEFI Shell's -sfo format is not supported: -data replaces it.
Managing boot entries
The firmware decides what to start from a list of boot entries kept in UEFI variables.
NESH shows and changes them safely with bootmgr, and also offers the UEFI Shell's bcfg.
How UEFI boots
flowchart LR
P["Power on"] --> N{"BootNext set?"}
N -- yes --> X["start Boot#### = BootNext<br/>(BootNext is cleared)"]
N -- no --> O["try the entries of BootOrder<br/>in order"]
O --> E["Boot####: description,<br/>device path, arguments"]
E --> L["boot loader, OS,<br/>or NESH"]
X --> L
What the firmware does at power-on
Variable
Content
Boot####
One boot entry (#### is its hexadecimal ID): description, device path of the file or device to
start, optional arguments, and flags active (used) and hidden (not shown in the firmware menu).
BootOrder
The list of IDs, in the order the firmware tries them.
BootNext
An ID to start once, at the next boot only.
BootCurrent
The ID used for the current boot (set by the firmware).
Timeout
Seconds the firmware boot menu waits.
Listing entries
fs0:\> bootmgr
BootCurrent: 0001 BootNext: - Timeout: 0 s
Ord Id Flg Description
1 0000 AH UiApp
Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(462CAA21-7614-4503-836E-8AB6F4662331)
2 0001 A * UEFI Misc Device
PciRoot(0x0)/Pci(0x2,0x0)
3 0002 A UEFI Non-Block Boot Device
PciRoot(0x0)/Pci(0x3,0x0)
4 0003 A EFI Internal Shell
Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(7C04A583-9E3E-4F1C-AD65-E05268D0B4D1)
Flags: A active, H hidden, * current boot, N next boot. '-' in Ord: not in the boot order.
bootmgr list -v also shows the arguments of each entry.
This creates a Boot#### entry that starts nesh.efi from that volume, and -t puts it first in the
boot order. Words after the description become the arguments passed to the program. Words starting with
- are read as options of bootmgr itself; to give the program such an argument, set the arguments
afterwards with bootmgr edit ID -a "-n".
Safety: dry run, confirmation, backups
Every bootmgr command that changes something follows the same steps:
Plan — it prints the changes it is going to make. With -n (dry run) it stops here.
Confirm — it asks Apply these changes? [y/N], unless -y is given.
(bootmgr next never asks: it only affects one boot.)
Back up — it saves all boot variables to \nesh\backup on the boot volume, unless -B
is given. If the backup cannot be written the change is not made.
Apply the changes.
bootmgr restore FILE puts back a saved state; bootmgr backup FILE saves one on demand.
Common tasks
Task
Command
Start an entry once, at the next boot
bootmgr next 0003, then reset
Make an entry the default
bootmgr top 0003
Set the whole order
bootmgr order 0003,0001,0002
Disable / enable an entry without deleting it
bootmgr disable 0002 / bootmgr enable 0002
Rename an entry, change its file or arguments
bootmgr edit 0003 -D "Ubuntu"
Delete an entry
bootmgr del 0004
Find entries whose file no longer exists
bootmgr check
Change the firmware menu timeout
bootmgr timeout 5
Work on driver entries (Driver####)
add -driver to the command
Reboot into the firmware setup
reset setup
The same information is available to scripts through bootmgr -data and the boot
functions; the boot menu example puts them together.
bcfg (UEFI Shell syntax)
bcfg works like in the UEFI Shell, using positions in the boot order rather than IDs:
bcfg boot dump, bcfg boot add 0 fs0:\efi\tools\nesh.efi "NESH", bcfg boot mv 3 0,
bcfg boot rm 2. It asks nothing (as in the UEFI Shell) but still saves a backup when it can. Existing UEFI
Shell scripts and instructions that use bcfg work as they are.
UEFI variables
UEFI variables are small named values stored by the firmware — most of them in non-volatile
memory (NVRAM). The boot entries, the Secure Boot keys, the language and the shell's own settings live there.
Names, GUIDs and attributes
A variable is identified by a name and a GUID (the “namespace” of its owner). Standard UEFI
variables use the global GUID. NESH knows a few GUIDs by name: global, security (Secure Boot
databases), shim, shell (UEFI Shell and NESH settings), systemd.
Attribute
Meaning
NV
Non-volatile: kept across reboots.
BS
Boot services: visible before the OS starts.
RT
Runtime: also visible to the operating system.
A
Authenticated: can only be changed with a signed update (Secure Boot keys).
The var command
fs0:\> var list Boot*
global BSRT 4 BootOptionSupport
global BSRT 2 BootCurrent
global NVBSRT 62 Boot0000
global NVBSRT 78 Boot0001
global NVBSRT 8 BootOrder
fs0:\> var get BootOrder
0000,0001,0002,0003
fs0:\> var set MyTool.Mode fast -g shell -t ascii
fs0:\> var save fs1:\vars.txt
fs0:\> var del MyTool.Mode -g shell
var get decodes the value when it can (numbers, strings, lists such as BootOrder); -x shows a hex
dump. var save writes variables to a readable text file and var load restores them.
The UEFI Shell commands dmpstore (dump, save, load and delete variables, with the same binary file format as
the UEFI Shell) and setvar are available too. Scripts use VAR$, VARNUM, SETVAR and the
other firmware functions.
Careful
Deleting or corrupting firmware variables can make a machine unbootable or reset its setup. Save them first
(var save or dmpstore -all -s FILE) and change only variables you understand.
Drivers and devices
UEFI firmware is built from drivers that find devices and offer services to programs.
These commands show how the pieces fit together, and let you load, connect and remove drivers.
Memory dump / read and write memory, I/O ports and PCI registers.
getmtc
The firmware's monotonic counter.
fs0:\> memmap -s
Type Pages MiB
Reserved 65672 256
LoaderCode 100 0
LoaderData 266 1
BootServicesCode 698 2
BootServicesData 9999 39
RuntimeCode 256 1
RuntimeData 581 2
Conventional 118412 462
ACPIReclaim 18 0
ACPINVS 514 2
Total memory: 511 MiB, available to the OS: 505 MiB
fs0:\> smbiosview -t 1
SMBIOS 2.8 (32-bit entry point at 0x1f988000), 9 structures
Type 1 (System Information) Handle 0x0100 Length 27
Manufacturer: QEMU
Product: Standard PC (Q35 + ICH9, 2009)
Version: pc-q35-10.0
Serial:
UUID: 00000000-0000-0000-0000-000000000000
SKU:
Family:
fs0:\> acpiview
RSDP at 0x1fb7e014, revision 2, OEM BOCHS
Sig Address Length Rev OEM Table
XSDT 0x1fb7d0e8 84 rev 1 BOCHS BXPC checksum ok
FACP 0x1fb79000 244 rev 3 BOCHS BXPC checksum ok
DSDT 0x1fb7a000 8474 rev 1 BOCHS BXPC checksum ok
FACS 0x1fbdd000 64 FACS
APIC 0x1fb78000 120 rev 3 BOCHS BXPC checksum ok
Screen resolution and text size
Two different things decide what you see:
The screen resolution (gop): how many pixels the firmware draws on.
The text console (mode): how many characters fit, in columns and rows. The firmware draws
each character in a fixed cell (8 x 19 pixels in the common EDK2 firmware), and it decides which text sizes exist
when it starts its console driver.
This is why the shell often uses only part of a large screen: a 100 x 31 text console covers 800 x 589 pixels, so on a
1920 x 1080 screen the text sits in a block in the middle. Three ways out, from the simplest:
fs0:\> mode -max
Text mode 2: 100 x 31 characters
fs0:\> mode -fill
Restarting the firmware console driver...
Text mode 4: 160 x 42 characters
fs0:\> gop -fit
Graphics mode 3: 800 x 600 (text 100 x 31)
mode -max takes the largest text size the firmware already offers. Try this first: on many machines
the firmware started its console at the screen's own resolution and a large mode is there.
mode -fill is for when mode only lists small sizes, which means the console driver
started at a low resolution. It restarts that driver (like reconnect -r), so the firmware builds a
text mode for the whole screen, and selects it. Two effects to know: the screen resolution goes back to the
firmware's own default, and the consoles are disconnected for a moment — on a serial console you may lose some
output.
gop -fit keeps the text size and lowers the resolution until the text fills the screen, which makes
the characters larger. Useful when you want big, readable text.
A high resolution and a full screen of text
Those two together depend on the firmware: the text modes are built when the console driver starts, so the
resolution has to be set before that. Many firmware setups have a “preferred resolution” or “video mode”
setting that is applied at the next boot; with that set, mode -max inside NESH is enough. Setting the
resolution afterwards with gop gives a large screen with the old, smaller text block.
To set a resolution for a program you are going to start (a graphical tool, a boot loader), use gop:
Command
Effect
gop
List the modes: number, resolution, pixel format, and the frame buffer.
gop 1024 768
Switch to that resolution.
gop 7
Switch to the mode with that number.
gop -max
The largest resolution available.
mode 100 31
A text size, from those mode lists.
If the new resolution is too small for the current text size, NESH switches the console to one that fits first, so the
text never ends up outside the screen.
Low-level access
mm and hexedit -m write directly to memory, I/O ports and PCI registers. A wrong value can hang the
machine or damage data. dmem only reads, but reading an unmapped address can also hang some machines.
These writes are disabled while Secure Boot is active.
Network
NESH uses the network stack of the firmware (the same one used for network boot) to configure
interfaces and download files over IPv4 and IPv6.
Making the network available
Most firmware loads its network drivers only when network boot (PXE) is enabled in the setup. If
ifconfig -l says no network interface, either enable network boot in the firmware setup, or load the
drivers from files with load (they are part of the firmware project EDK2; a copy extracted from the firmware of
the same machine works best):
The network drivers need a random number generator, which modern machines provide.
IPv4
fs0:\> ifconfig -s eth0 dhcp
eth0: waiting for DHCP... done
name : eth0
media state : unknown
policy : dhcp
mac addr : 52-54-00-12-34-56
ipv4 address : 10.0.2.15
subnet mask : 255.255.255.0
gateway : 10.0.2.2
dns server : 10.0.2.3
route table :
subnet 10.0.2.0 netmask 255.255.255.0 gateway 0.0.0.0
subnet 0.0.0.0 netmask 0.0.0.0 gateway 10.0.2.2
A fixed address: ifconfig -s eth0 static 192.168.1.10 255.255.255.0 192.168.1.1, DNS servers with
ifconfig -s eth0 dns 192.168.1.1, back to DHCP with ifconfig -r. The settings are kept by the firmware.
IPv6
Every interface has a link-local address (fe80::…). ifconfig6 -s eth0 auto enables automatic
configuration from the routers of the network; ifconfig6 -s eth0 man host 2001:db8::10/64 gw 2001:db8::1
sets an address by hand.
fs0:\> ping -n 3 10.0.2.2
Ping 10.0.2.2 16 data bytes.
16 bytes from 10.0.2.2 : icmp_seq=1 ttl=255 time=0ms
16 bytes from 10.0.2.2 : icmp_seq=2 ttl=255 time=0ms
16 bytes from 10.0.2.2 : icmp_seq=3 ttl=255 time=0ms
3 packets transmitted, 3 received, 0% packet loss
Rtt(round trip time) min=0ms max=0ms avg=0ms
fs0:\> tftp 10.0.2.2 hello.txt fs1:\tftp.txt
Downloading hello.txt from 10.0.2.2 ...
20 bytes saved to fs1:\tftp.txt
fs0:\> http http://[fec0::2]:18080/tool.efi fs1:\tool.efi
ping, tftp and http accept both IPv4 and IPv6 addresses; in URLs an IPv6 address goes in square
brackets. ping6 is also available for UEFI Shell compatibility. http supports http:// only
(https needs a TLS driver in the firmware).
' download a diagnostic tool from a server and run it
RUN "ifconfig -s eth0 dhcp"
IF ERR <> 0 THEN PRINT "no network": END 1
RUN "http", "http://192.168.1.5/tools/diag.efi", "fs1:\diag.efi"
IF ERR = 0 THEN RUN "fs1:\diag.efi"
Running EFI applications
NESH starts UEFI programs — boot loaders, firmware updaters, diagnostics, other shells — and
gives them the environment they expect.
Type the file name with its arguments: fs1:\tools\flash.efi -update bios.bin. The .efi extension
can be omitted, and names are searched along path.
The program's exit status becomes the exit code (ERR in scripts).
Its text output can be saved with > file or captured with RUN$.
Programs written for the UEFI Shell (with the EDK2 ShellLib) work: NESH provides the UEFI Shell programming
interface (EFI_SHELL_PROTOCOL 2.2) with the same volumes, current directory, environment variables and aliases,
and lets them run shell commands. The EDK2 versions of edit, pci or ping, for example, run
unchanged.
load is for drivers; applications are refused by load.
Programs designed only for the old EFI 1.10 shell interface (from before 2009) are not supported.
Secure Boot
With Secure Boot active, the firmware starts only programs signed with a trusted key. NESH is
one file, so one signature covers the whole shell.
Signing nesh.efi
To run NESH on a machine with Secure Boot, sign nesh.efi with a key the machine trusts. With your own keys
(on Linux, with the sbsigntools package):
The certificate must be in the firmware's db database (enrolled from the firmware setup or with your platform's
key-management tools), or — on machines that boot through shim — in the MOK list (mokutil --import db.der).
What changes when Secure Boot is active
NESH shows Secure Boot is active: low-level hardware writes are disabled when it starts, and refuses writes that
could be used to get around the protection:
Refused
Still allowed
mm ADDRESS VALUE and interactive changes in mm (memory, MMIO, I/O ports, PCI registers)
Reading with mm, dmem, pci
Saving memory in hexedit -m
Viewing memory in hexedit -m
In addition, the firmware itself refuses to load unsigned drivers and programs (load, loadpcirom,
starting .efi files); NESH reports this as not allowed by Secure Boot (the image is not signed by a trusted
key). Authenticated variables, such as the Secure Boot keys, cannot be changed either. Ordinary UEFI variables,
files, the clock and the serial port settings keep working. Scripts can check the state with SECUREBOOT.
Differences from the UEFI Shell
For people who know the UEFI Shell: what is the same, what is different, and how to translate.
UEFI Shell
NESH
.nsh scripts with if, for, goto, shift, %1
Not supported: write .nsb scripts in NESH BASIC. %1 → ARG$(1); if exist →
IF FILEEXISTS(…); %lasterror% → ERR.
Not included (reading a missing model-specific register can hang the machine).
exit /b
Same meaning: ends only the current script.
Separate IPv6 tools
ifconfig6 and ping6 exist; ping, tftp, http also accept IPv6.
Everything else — command names, their options, volume names, environment variables and aliases (stored in the same
UEFI variables, so both shells share them), dmpstore files, bcfg — works as in the UEFI Shell. NESH adds
commands the UEFI Shell does not have: bootmgr, var, grep, head, tail, wc,
hexdump, stat, which, history, sysinfo, cpuid, gop, devtree and more.
Troubleshooting
Problem
What to try
The firmware does not show the USB stick
The stick must be FAT-formatted and contain
\EFI\BOOT\BOOTX64.EFI. Some firmware needs “USB boot” enabled or “fast boot” disabled in the setup.
“Security violation” or nothing happens when starting NESH
Secure Boot is active and nesh.efi is not
signed with a trusted key: see Signing nesh.efi, or disable Secure Boot in the setup.
A disk or stick is missing from map
connect -r, then map -r. Partitions with a file system the
firmware does not know (NTFS, ext4) appear only as blkN.
“command not found”
Check the spelling with help; for a script or program, give the path or check
set path and which NAME.
A long output scrolls away
It should stop at every screenful; if it does not, check set pager
(see Long output: paging), or save it to a file with > file.
The shell uses only part of the screen
mode -max, then mode -fill if the text sizes offered are
all small; gop -fit makes the characters larger instead (see Screen resolution and text size).
Function keys do not work (serial console)
Use the Ctrl equivalents listed for each editor.
History or backups are not saved
The boot volume is read-only; NESH continues without them.
A script stops with “error: …”
The message gives file and line. nesh.efi -k SCRIPT checks the syntax.
Every command, grouped by topic. These texts are the same ones that help NAME shows
inside NESH (this chapter is generated from them). Commands marked -data support
script-friendly output.
help [COMMAND | STATEMENT | FUNCTION | basic | functions]
help list all the commands with a one-line summary
help NAME usage and details of one command
help PRINT a statement or function of the language: the lines
about it from the references below
help basic quick reference of the BASIC scripting language
help functions list of the built-in BASIC functions
Names are not case-sensitive. 'help language' and 'help func' also work.
An unknown NAME is an error.
ver-data
Show shell, firmware and UEFI versions
ver
ver shell version and platform; on UEFI also the firmware
vendor and revision, UEFI version and Secure Boot state
With -data: shell, version, platform, firmware, firmware_revision, uefi,
secure_boot (yes/no).
cls
Clear the screen
cls [BACKGROUND]
cls clear the screen
cls 1 set a blue background, then clear
BACKGROUND: 0 black, 1 blue, 2 green, 3 cyan, 4 red, 5 magenta, 6 brown,
7 light gray. The screen is not cleared when the output is redirected.
exit
Leave the shell and return to the firmware
exit [/b] [CODE]
exit leave the shell with exit code 0
exit 3 leave the shell with exit code 3
exit /b 2 end only the current script, with exit code 2
In a script (RUN "exit"), exit stops all running scripts at once, then
leaves the shell. exit /b is like END CODE; at the prompt it only sets the
exit code. CODE may be decimal or hex (0x10). -b is the same as /b.
history
Show the last N commands (-c clears the history)
history [-c] [N]
Keys at the prompt: Up/Down browse the history, Ctrl-R searches it,
Tab completes commands and paths, Ctrl-A/E start/end of line,
Ctrl-K/U delete to end/start, Ctrl-W delete word, Ctrl-L clear screen.
echo
Print text (-n: no newline)
echo [-n] [TEXT...]
echo TEXT... print the words separated by one space, then a newline
echo -n TEXT... the same without the final newline
echo "a b" quotes keep the spaces
Only a first -n is an option; any other word is printed as it is,
including -b (echo never pages).
echo -on and echo -off (UEFI Shell script switches) do nothing.
pause
Wait for a key
pause [-q] [MESSAGE]
pause print "Press any key to continue..." and wait
pause Insert disk print your own message and wait for a key
pause -q wait without a message
Exit code 0 for most keys, 130 for Esc or Ctrl-C. In a script, Esc can be
tested in ERR; Ctrl-C also stops the script.
sleep
Wait for the given time
sleep MILLISECONDS
sleep 500 wait half a second
Ctrl-C stops the wait (exit code 130). For microseconds see stall.
which
Show what a command name refers to
which NAME...
which NAME... say if NAME is an alias, a built-in command, a file
or a BASIC function
which ls ls: built-in command
which ll ll: alias for ls -l
Files are searched like commands: NAME.nsb and NAME.efi in the directories
of the path variable, or at the path given. Exit code 127 if a NAME is not
found.
set-data
Show or change environment variables
set [-v] [NAME [VALUE...]] | set -d NAME
set list all the variables
set NAME show one variable
set NAME VALUE set a variable, kept in the firmware across reboots
set -v NAME VALUE set a temporary variable (lost when the shell exits)
set -d NAME delete a variable
Environment variables are shared with the EFI applications started by
the shell and are separate from BASIC variables. In scripts: ENV$(name$),
SETENV, DELENV. path lists the directories searched for commands (';'
separated, '.' = current directory). pager=off stops the automatic
paging of long output at the prompt. Read-only: cwd, lasterror,
uefishellsupport, uefishellversion, uefiversion, neshversion.
With -data (set): name, value, kind (permanent, temporary, readonly).
alias-data
Show or define command aliases
alias [-v] [NAME [COMMAND...]] | alias -d NAME
alias list the aliases (V: temporary)
alias ll ls -l define ll, kept in the firmware across reboots
alias -v ll ls -l temporary alias
alias -d ll delete an alias
Extra arguments are appended: 'll fs0:' runs 'ls -l fs0:'.
reset
Restart or shut down the machine, or reboot into the firmware setup
(none), -c cold reset
-w warm reset
-s shut down (power off)
setup, -fwui, -f restart into the firmware setup screen (sets the
OsIndications variable; the firmware must support it)
STRING reset reason passed to the firmware as ResetData
Only one mode may be given. If the firmware does not reset, reset fails
with an error.
Example: reset -s "maintenance"
sysinfo-data
Firmware, CPU, memory and display information
sysinfo
Shows firmware vendor and revision, UEFI version, Secure Boot state, CPU,
memory size, console size, graphics mode, configuration tables and the
volume NESH was started from. Arguments are ignored.
With -data: one record with firmware, firmware_revision, uefi,
secure_boot, cpu, cpu_vendor, memory, console_columns, console_rows,
graphics_width, graphics_height, framebuffer, config_tables, acpi,
smbios, boot_volume, boot_devpath.
Set the size of files (truncate or extend with zeros)
ls-data
List files and directories
ls [-l] [-r] [-a[ashrd]] [PATH | PATTERN...]
ls names in the current directory
ls -l fs1:\efi details: date, time, attributes, size, name
ls -r also every subdirectory
ls *.efi only matching names
-a also hidden and system files
-aXY only entries with all the attributes X, Y...:
d directory, r read-only, h hidden, s system,
a archive (e.g. ls -ad lists directories)
Directory names end with \ (and are blue; programs .efi/.nsb are green).
Hidden and system files are left out unless -a is given or a pattern
names them. -b pages the output (see help more). dir is the same as
ls -l.
With -data: name, path, type, size, modified, readonly, hidden, system,
archive (one record per entry).
dir-data
List files with details (same as ls -l)
dir [-r] [-a[ashrd]] [PATH | PATTERN...]
dir current directory
dir -r fs0:\efi also all subdirectories
dir *.efi only matching names (hidden files included)
Each line: date, time, attributes (d dir, r read-only, h hidden, s system,
a archive), size and name; a total line ends each directory. Hidden and
system files are shown only with -a. -l is accepted and has no effect;
-b pages the output. Other options as for ls.
With -data: name, path, type, size, modified, readonly, hidden, system,
archive.
cd
Change the current directory
cd [DIR | fsN:]
cd print the current directory
cd DIR go to DIR (relative, or absolute from the root)
cd fs1: go to the root of volume fs1:
cd .. go to the parent directory
Both \ and / work as separators. DIR must be an existing directory.
pwd
Print the current directory
pwd
Prints the full path, e.g. fs0:\efi\boot (same as cd with no arguments).
cat
Print files (UTF-8 or UCS-2 text, detected automatically)
cat [-a|-u] FILE...
cat readme.txt print a file
cat fs0:\logs\*.txt print all matching files, one after another
Files may be UTF-8 (with or without BOM) or UCS-2 little-endian with BOM;
carriage returns are removed. -a and -u (UEFI Shell: force ASCII or
UCS-2) are accepted before the files and ignored. Ctrl-C stops.
type
Print files (same as cat)
type [-a|-u] FILE...
Same as cat (UEFI Shell name).
more
Print files one screen at a time
more FILE...
more log.txt stop at every screenful: Enter one line,
Space one page, q stops
Same as cat, with paging always on (cat pages too when you type it at
the prompt). Any command pages with -b; 'set pager off' turns the
automatic paging of the prompt off.
cp
Copy files (-r directories too)
cp [-r] [-q] SRC... DST
-r copy directories and all their contents
-q accepted for UEFI Shell compatibility (cp never asks)
cp a.txt b.txt copy a file
cp *.efi fs1:\tools copy several files into a directory
cp -r fs0:\efi fs1:\backup copy a whole folder
If DST is an existing directory, each SRC is copied into it; with several
sources DST must be a directory. Existing files are overwritten without
asking; with -r, existing directories are merged. A directory cannot be
copied into itself. After an error or Ctrl-C the partial file is deleted.
mv
Move or rename files and directories
mv SRC... DST
mv old.txt new.txt rename a file
mv *.log fs0:\logs move files into a directory
mv fs0:\tools fs1:\ move a directory to another volume
If DST is an existing directory, each SRC is moved into it; with several
sources DST must be a directory. An existing file at the target is
replaced without asking, but only once the move has succeeded (if not,
it is put back); an existing directory is an error. Between volumes, mv
copies and deletes the source only after a complete copy (a partial copy
is removed). There are no options.
rm
Delete files (-r or -q: directories too, -f ignore missing)
rm [-r] [-f] [-q] PATH...
-r, -q also delete directories with all their contents
-f no error for paths or patterns that match nothing
rm *.tmp delete matching files
rm -r fs1:\old delete a directory tree
Nothing is asked before deleting. Read-only files cannot be deleted:
clear the flag with attrib -r first. The root of a volume is never
removed. -q is the UEFI Shell form (there rm deletes directories too).
del
Delete files (same as rm)
del [-r] [-f] [-q] PATH...
Same as rm (UEFI Shell name).
mkdir
Create directories (-p also the parents)
mkdir [-p] DIR...
-p also create missing parents; no error if a directory exists
mkdir -p fs0:\a\b\c create a whole path in one step
Without -p the parent must exist and DIR must not exist yet. A file with
the same name as DIR or a parent is always an error.
md
Create directories (same as mkdir)
md [-p] DIR...
Same as mkdir (UEFI Shell name).
rmdir
Remove empty directories
rmdir DIR...
rmdir fs0:\old remove an empty directory
A directory that is not empty is an error (use rm -r to delete a whole
tree). Wildcards are not expanded.
touch
Set the modification time to now (creates missing files; -r recursive)
touch [-r] FILE...
-r also every file and directory inside the given directories
touch log.txt create an empty file, or update its time
touch -r fs0:\data update a whole tree
Wildcards are allowed; a pattern that matches nothing is skipped silently.
stat-data
Show file details
stat PATH...
stat boot.efi path, type, size, modified time, attributes
Size is not shown for directories. Wildcards are not expanded.
With -data: name, path, type, size, modified, readonly, hidden, system,
archive.
attrib
Show or change file attributes (archive, system, hidden, read-only)
attrib [+a|-a] [+s|-s] [+h|-h] [+r|-r] [FILE | DIR | PATTERN...]
attrib attributes of everything in the current dir
attrib DIR attributes of the entries in DIR
attrib +r boot.efi make a file read-only
attrib -h -s fs0:\* clear hidden and system on all root entries
Letters: a archive, s system, h hidden, r read-only (upper case works).
Each line shows D (directory), A, S, H, R and the path. When changing, a
directory itself is changed, not its contents. Wildcards are allowed.
comp
Compare two files and show where they differ
comp [-n COUNT|all] [-s BYTES] FILE1 FILE2
-n COUNT stop after COUNT differences (default 10; all: no limit)
-s BYTES bytes shown for each difference (default 16)
comp -n all old.rom new.rom list every difference
A run of consecutive different bytes is one difference: its hex offset is
printed, then the bytes of both files in hex and as text. Different sizes
count as one more difference. ERR is nonzero if the files differ. Both
files are read into memory.
cmp
Compare two files and stop at the first difference
cmp [-s BYTES] FILE1 FILE2
Same as comp -n 1. -s BYTES sets the bytes shown (default 16).
setsize
Set the size of files (truncate or extend with zeros)
setsize SIZE FILE...
setsize 1048576 disk.img make a file of 1 MiB
setsize 0 log.txt empty a file
SIZE is in bytes (decimal, or hex with 0x). Missing files are created
first, as in the UEFI Shell.
-i ignore upper/lower case
-v print the lines that do NOT contain TEXT
-n put the line number before each line
-c print only the number of matching lines
grep -i error log.txt lines containing "error", any case
grep -c TODO *.nsb matching lines in each script
TEXT is plain text, not a pattern. FILE may contain wildcards; with several
files each line starts with the file name. UTF-8 and UCS-2 files are read;
directories are skipped. Use -- before a TEXT that starts with '-'.
Exit code: 0 if a line matched, 1 if none, other values on errors.
head
First N lines of a file (default 10)
head [-n N] FILE
-n N print the first N lines (default 10)
head -n 20 log.txt the first 20 lines
The file is read as text (UTF-8 or UCS-2; carriage returns are removed).
One FILE only; -n goes before it.
tail
Last N lines of a file (default 10)
tail [-n N] FILE
-n N print the last N lines (default 10)
tail -n 5 log.txt the last 5 lines
The file is read as text (UTF-8 or UCS-2; carriage returns are removed).
One FILE only; -n goes before it.
wc
Count lines, words and bytes
wc FILE...
wc a.txt b.txt one line per file: lines, words, bytes, name
Lines are counted as newline characters; words are separated by spaces,
tabs or newlines; bytes is the file size. Wildcards are not expanded.
hexdump
Hexadecimal dump of a file
hexdump [-s OFFSET] [-n LENGTH] FILE
-s OFFSET start at byte OFFSET (default 0)
-n LENGTH dump at most LENGTH bytes (default: to the end)
hexdump -n 0x200 disk.img the first 512 bytes
Each line shows the offset, 16 bytes in hex and the printable characters.
Numbers may be decimal or hex (0x). Options go before FILE. Ctrl-C stops.
date-data
Show or set the date
date [YYYY-MM-DD | MM/DD/YYYY | MM/DD/YY]
date show the date as YYYY-MM-DD
date 2026-09-19 set the date
date 09/19/2026 set the date, UEFI Shell order (MM/DD/YYYY or MM/DD/YY)
A two-digit year means 20YY. The time of day is not changed.
With -data: date, year, month, day.
time-data
Show or set the time
time [HH:MM[:SS]]
time show the time as HH:MM:SS (24 hours)
time 14:30 set the time (seconds become 0)
time 14:30:15 set the time with seconds
The date is not changed.
With -data: time, hour, minute, second.
timezone
Show or set the time zone of the clock (-l list, -f details)
timezone [-s [+|-]hh:mm] [-l] [-f]
(none) show the time zone of the real-time clock
-s [+|-]hh:mm set the offset from UTC (up to 14:00; :mm optional)
-l list common offsets with example places
-f also show the raw TimeZone and Daylight fields
-b page the output (UEFI Shell option, see help more)
-s changes only the time zone, not the date and time. -l ignores the
other options.
Example: timezone -s +01:00
parse
Extract a column from standard-format (comma separated) output
Lines look like: TableName,"value1","value2",... COLUMN 1 is value1.
-i N: only the Nth line of TABLE.
-s N: only in the Nth ShellCommand section.
stall
Wait for the given number of microseconds
stall MICROSECONDS
stall 1000 wait 1000 microseconds (1 ms)
Uses the firmware Stall service: the wait cannot be stopped with Ctrl-C.
For longer waits use sleep (milliseconds, can be stopped).
eficompress
Compress a file in the UEFI compression format
eficompress INFILE OUTFILE
eficompress big.bin big.cmp compress big.bin into big.cmp
Writes the UEFI (EFI 1.1) compressed format, which firmware and efidecompress
can read. OUTFILE is overwritten. Prints the sizes before and after.
efidecompress
Decompress a file in the UEFI compression format
efidecompress [-n] INFILE OUTFILE
-n use the NESH decoder even if the firmware has one
efidecompress big.cmp big.bin decompress big.cmp into big.bin
By default the firmware decompressor is used when available. OUTFILE is
overwritten. Prints the sizes before and after.
List volumes and block devices; give volumes extra names
map [-r] [-v] [-t fs|blk] | map NAME TARGET | map -d NAME
map volumes (fsN:) and block devices (blkN:)
map -r rescan the devices (also -u)
map usb fs1: fs1: can also be called usb:
(TARGET: fsN:, blkN: or a handle)
map -d usb remove an extra name
vol-data
Show a volume, set (-n) or delete (-d) its label
vol [fsN:] [-n LABEL | -d]
vol current volume: label, total and free space
vol fs1: another volume (also fs1, a map name or a path)
vol fs1: -n BOOTDISK set the label (at most 11 characters)
vol -d delete the label of the current volume
A label cannot contain % ^ * + = [ ] | : ; " < > ? / or a dot.
With -data: volume, label, size, free, readonly.
dblk
Show raw blocks of a disk, decoding MBR, GPT and FAT boot sectors
dblk DEVICE [LBA [COUNT]]
DEVICE blkN (see map), fsN: or a handle number (hex)
LBA first block (hex, default 0)
COUNT number of blocks (hex, 1 to 10, default 1)
-b page the output (UEFI Shell option, see help more)
Each block is shown in hex and text. An MBR (LBA 0), a GPT header (LBA 1)
and FAT boot sectors are also decoded. COUNT stops at the end of the
device. The disk is only read.
Example: dblk blk0 1
getmtc
Show the next monotonic count of the firmware
getmtc
Prints the 64-bit monotonic counter of the firmware in hex. Each call
increases it, so two runs never show the same value.
Show, set or delete a UEFI variable (UEFI Shell syntax)
bootmgr-data
Manage the UEFI boot entries
bootmgr [SUBCOMMAND] [OPTIONS]
list [-v] entries in boot order (default)
add FILE "DESC" [ARGS] [-t] new entry for FILE (-t: first in the order)
del ID delete an entry
enable ID | disable ID activate / deactivate an entry
edit ID [-D DESC] [-a ARGS] [-F FILE] change an entry
order [ID,ID,...] show or set the boot order
top ID move an entry to the top of the order
next ID | next -d entry for the next boot only / clear it
timeout [SECONDS] firmware boot menu timeout
backup FILE | restore FILE save / restore all the boot variables
check find entries pointing to missing files
Common options: -n dry run (show, change nothing), -y do not ask,
-B no automatic backup, -driver work on Driver#### entries.
IDs are the hexadecimal numbers of Boot#### (e.g. 0003).
Before every change a backup is saved in \nesh\backup on the boot volume.
To start an EFI file now, type its name (or RUN it in a script).
With -data (list): one record per entry, plus one with the boot settings.
# is the position in BootOrder/DriverOrder (hex, as shown by dump).
dump [-v] list the options in order
add # FILE "DESC" new option for FILE at position # (full device path)
addp # FILE "DESC" same with a short-form path (partition + file)
addh # HANDLE "DESC" new option for the device path of a handle
rm # delete the option at position #
mv # # move an option to another position
mod # "DESC" change the description
modf|modp|modh # ... change the file (full / short path) or use a handle
-opt # [FILE|"TEXT"] optional data: a file's content or a text (UCS-2);
without it the optional data is cleared
No confirmation is asked; a backup is saved in \nesh\backup when possible.
See also: bootmgr (NESH syntax, with dry run and confirmation).
var-data
Read and write UEFI variables
var list|get|set|del|save|load ...
var list [PATTERN] [-g GUID] list variables (e.g. var list Boot*)
var get NAME [-g GUID] [-x|-s|-n] [-v]
show a value (-x hex dump, -s string,
-n number)
var set NAME VALUE [-g GUID] [-t TYPE] [-a ATTR]
TYPE: str (UCS-2, default), ascii, u8, u16, u32, u64, hex, file
ATTR: nv,bs,rt (default for new variables; existing ones keep
theirs)
var del NAME [-g GUID] delete a variable
var save FILE [PATTERN] [-g GUID] save variables to a text file
var load FILE restore variables saved with var save
GUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx or a name: global (default),
security, shim, shell, systemd.
With -data (var list): name, guid, guid_name, attributes, size.
dmpstore
Dump, delete, save or load UEFI variables (UEFI Shell syntax)
dmpstore all variables with the global GUID
dmpstore -all variables of every GUID
dmpstore Boot* variables matching a pattern
dmpstore NAME -d delete (asks when a pattern matches several)
dmpstore -all -s FILE save to a file (binary format of the UEFI Shell)
dmpstore -l FILE load variables from such a file
See also: var (NESH syntax).
setvar
Show, set or delete a UEFI variable (UEFI Shell syntax)
setvar NAME [-guid GUID] [-bs] [-rt] [-nv] [=DATA...]
setvar NAME show the value
setvar NAME -nv -rt =0100 set hexadecimal bytes
setvar NAME ="text" ASCII text (no terminator)
setvar NAME =L"text" UCS-2 text (with terminator)
setvar NAME =--PciRoot(0) binary device path from its text form
setvar NAME = delete the variable
Without -bs/-rt/-nv an existing variable keeps its attributes; a new one
is temporary (boot services only).
drivers one line per driver
drivers -l fr driver names in another language, if the driver has it
Columns: DRV driver handle, VERSION driver version (hex), TYPE, CFG and DIAG
(X: supports drvcfg / drvdiag), #D devices it manages, #C child devices it
created, driver name (default language en) and the file it was loaded from.
TYPE B is a bus driver: it created child devices (e.g. one per USB device);
D is a device driver (a bus driver with no children yet also shows D).
Handle numbers are hexadecimal; -b pages the output.
With -data: handle, version, type, config, diag, controllers, children,
name, image.
devices-data
List the devices (controllers) and their drivers
devices [-l LANG]
devices one line per device (controller)
Columns: CTRL device handle, TYPE (R root: no parent, B bus: has children,
D device), CFG and DIAG (X: one of its drivers supports drvcfg / drvdiag),
#P parents, #D drivers managing it, #C children, device name.
A device is a handle with a device path that is not an image or a driver.
Names come from the drivers (in English) or else from the device path;
-l is accepted and ignored; -b pages the output.
With -data: handle, type, config, diag, parents, drivers, children, name.
devtree
Show the device tree (-d: device paths)
devtree [-d] [-l LANG] [HANDLE]
devtree tree of all devices, from the root devices down
devtree HANDLE only the device HANDLE and what is below it
devtree -d show device paths instead of names
Each line is "Ctrl[HANDLE] name"; children are indented under their parent.
A device without a device path shows up to 4 of its protocols in <...>.
-l is accepted and ignored; -b pages the output.
Example: devtree -d 3F device paths of device 3F and its children
dh-data
Show handles and their protocols
dh [-d|-v] [-p PROTOCOL] [HANDLE]
dh one line per handle: number and protocol names
dh HANDLE details of one handle (device path, image, driver, disk...)
dh -p BlockIo only handles with a protocol (name or GUID)
dh -d details of all handles
Handle numbers are hexadecimal and stay the same during the session.
With -data: handle, name, protocols (and devicepath with -d or HANDLE).
openinfo
Show who opened the protocols of a handle
openinfo HANDLE
openinfo HANDLE each protocol of HANDLE and who has it open
For each protocol, one line per user: Drv[agent handle] Ctrl[controller
handle] Cnt(open count), how it is open, and the agent's image name.
How: Driver (a driver manages the device), Exclusive, Driver+Exclusive,
Child (used by a child device), HandProt / GetProt / TestProt (simple use).
Handles are hexadecimal (see dh); -b pages the output.
connect
Connect drivers to devices (no handle: all; -r recursive; -c consoles)
connect [-r] [-c] [[DRIVER] CONTROLLER]
connect connect all drivers to all devices (recursive)
connect CONTROLLER connect the best drivers to one device
connect DRIVER CONTROLLER connect only DRIVER to that device
-r also connect the new child devices, recursively
-c connect the consoles (ConIn, ConOut, ErrOut)
Connecting asks drivers to start managing a device. Bus drivers then create
child devices (e.g. the partitions of a disk, which then get a file system).
With -c and handles, the consoles are connected first, then the device.
Exit code is nonzero if the firmware reports an error for the device.
Example: connect -r 3F connect device 3F and everything below it
disconnect
Disconnect drivers from a device (-r: all devices, consoles reconnected)
disconnect CONTROLLER stop all drivers managing a device
disconnect CONTROLLER DRIVER stop only DRIVER on that device
disconnect CONTROLLER DRIVER CHILD make DRIVER release one child device
disconnect -r disconnect all devices, then connect
the consoles again (screen, keyboard)
When a bus driver stops, the child devices it created disappear too.
DRIVER is a driver handle (see drivers); -r is ignored when handles are given.
Exit code is nonzero if the firmware reports an error.
reconnect CONTROLLER disconnect all drivers, connect again
reconnect CONTROLLER DRIVER the same, only for DRIVER
reconnect CONTROLLER DRIVER CHILD release one child, then connect DRIVER
reconnect -r disconnect and connect all devices
The connect step is recursive (child devices are connected too) and runs
only if the disconnect succeeded; -r is ignored when handles are given.
Exit code is nonzero if a step fails.
load
Load UEFI drivers (-nc: do not connect them to devices)
load [-nc] FILE...
load FILE... load and start drivers, then connect all devices
load -nc FILE... load and start drivers, but do not connect them
FILE may contain wildcards. Applications are refused (run them by typing
their name), and so are drivers not allowed by Secure Boot.
The connect step runs if at least one driver was loaded and started.
Exit code is nonzero if any file fails.
Example: load fs0:\drivers\MyDxe.efi load a driver and connect it
unload
Unload an image (-n: no question, -v: show details)
unload [-n] [-v] HANDLE
unload HANDLE unload an image, after asking for confirmation
unload -n HANDLE do not ask
unload -v HANDLE show the handle details (like dh HANDLE) first
HANDLE must be a loaded image (see dh -p LoadedImage); for most drivers it
is the DRV number shown by drivers. -verbose is the same as -v.
Many drivers cannot be unloaded: the result is then "not supported".
Exit code is nonzero on error or if you do not answer y.
drvdiag list driver/device pairs that offer diagnostics
-s run the standard diagnostics
-e run the extended diagnostics
-m run the manufacturing diagnostics
-c also include the child devices of each device
-l LANG language of the messages (default en)
Handles narrow the selection: DRIVER, then CONTROLLER, then CHILD.
Each line shows Drv[..] Ctrl[..] (Child[..]) and the driver name, or the
result ("passed" or the error) and the driver's message.
Only drivers with the Driver Diagnostics 2 protocol are used.
Exit code is nonzero if a test fails.
Example: drvdiag -s 7A standard tests of driver 7A on all its devices
drvcfg list driver/device pairs with a configuration protocol
-s set options: the driver asks for its settings
-v check that the current settings are valid
-f TYPE restore defaults: 0 safe, 1 manufacturing (other
numbers are passed to the driver)
-c also include the child devices of each device
-l LANG language used by -s (default en)
Handles narrow the selection: DRIVER, then CONTROLLER, then CHILD.
After -s or -f the driver may ask to stop or restart the controller or the
platform: the line says so ("action required").
Only the Driver Configuration 2 protocol is used. If none is found, the
handles with HII setup forms are listed (use the firmware setup menu).
Exit code is nonzero if an operation fails.
Load the UEFI drivers contained in a PCI option ROM file
memmap-data
Show the UEFI memory map (-s summary only)
memmap [-s] [-b]
(none) every memory descriptor, then totals per type
-s totals per type only
-b page the output (UEFI Shell option, see help more)
Start and End are physical addresses; a page is 4 KiB. Total memory
excludes reserved and MMIO ranges; "available to the OS" counts
conventional, loader and boot services memory.
With -data: type, start, end, pages, attributes (one record per
descriptor); with -s: type, pages, bytes (one record per type).
dmem
Show memory (hex; no address: the system table and configuration tables)
dmem [ADDRESS [SIZE]] [-MMIO]
ADDRESS start address (hex); without it, dmem dumps the EFI system
table and lists the configuration tables (GUID and address)
SIZE bytes to show (hex, default 0x200, max 0x100000)
-MMIO read through the PCI root bridge of segment 0
-b page the output (UEFI Shell option, see help more)
Read-only. Reading an unmapped address can hang the machine.
Example: dmem 0xFED00000 40 -MMIO
mm
Read or write memory, I/O ports or PCI configuration space
mm ADDRESS [VALUE] [-w 1|2|4|8] [-MEM|-MMIO|-IO|-PCI|-PCIE] [-n]
mm ADDRESS show the value and let you type new ones
(Enter: next address, q: quit)
mm ADDRESS VALUE write VALUE
-n only show the value
-w 1|2|4|8 access width in bytes (default 1)
-MEM memory (default) -MMIO memory-mapped I/O
-IO I/O port
-PCI address 0x000000ssbbddffrr (segment, bus, device,
function, register)
-PCIE address 0x0000ssbbddfffrrr (register up to 0xFFF)
Numbers are hexadecimal. Writes are refused while Secure Boot is active.
pci-data
List PCI devices, or show the configuration space of one device
pci [BUS DEV [FUNC]] [-s SEG] [-i] [-ec]
pci list every device: segment, bus, device, function,
class, vendor and device ID
pci BUS DEV [FUNC] hex dump of the configuration space (FUNC 0 by default)
-i also decode the header: IDs, class, command/status,
BARs, bus numbers, interrupt, capabilities
-ec dump the 4 KiB PCI Express extended space
-s SEG PCI segment (default: all segments when listing, 0 else)
-b page the output (UEFI Shell option, see help more)
Numbers are hexadecimal: pci 0 1f 3 -i decodes device 00:1F.3.
With -data: one record per function (segment, bus, device, function, vendor,
deviceid, class, classname); for one device, the decoded header.
smbiosview-data
Show the SMBIOS tables (BIOS, system, board, CPU, memory...)
smbiosview [-t TYPE] [-h HANDLE] [-s]
smbiosview every structure, with the fields NESH decodes
-t TYPE only one type (decimal): 0 BIOS, 1 system, 2 board,
3 enclosure, 4 processor, 16 memory array, 17 memory
device, 19 mapped address
-h HANDLE only the structure with this handle (hexadecimal)
-s statistics: how many structures of each type
-a accepted for UEFI Shell compatibility, ignored
-b page the output (UEFI Shell option, see help more)
smbiosview -t 17 memory modules: slot, size, speed, part number
With -data: one record per structure (type, typename, handle, length and the
decoded fields, e.g. vendor, version, serial, size).
acpiview-data
List the ACPI tables, or show or save one
acpiview [-l] | acpiview -s SIG [-d]
acpiview list the tables: signature, address, length, revision,
OEM, checksum (-l does the same)
-s SIG show one table: summary of APIC, MCFG, HPET and FACP,
then a hex dump (SIG is case-insensitive, e.g. apic)
-s SIG -d save the table to SIG.bin in the current directory
(SIG2.bin... when there are several)
-r, -q, -h accepted for UEFI Shell compatibility, ignored
With -data: one record per table (signature, address, length, revision,
oemid, oemtable, checksum); -d cannot be combined with -data.
cpuid
Show processor information (or raw CPUID registers)
cpuid [LEAF [SUBLEAF]]
(none) vendor, family, model, stepping and main features
LEAF [SUBLEAF] raw EAX, EBX, ECX, EDX of one leaf (SUBLEAF default 0)
LEAF and SUBLEAF are hexadecimal. Family, model and stepping print in hex.
Example: cpuid 80000001
mode
List the text modes or select one
mode [COLUMNS ROWS | -max | -fill]
(none) list the text modes of the console (current one marked)
COLUMNS ROWS switch to the mode with exactly this size
-max switch to the mode with the most characters
-fill make the text use the whole screen: restarts the
firmware console driver (as reconnect -r does), which
then offers a mode for the whole screen, and selects it
The firmware decides which text modes exist, from the screen resolution
it had when it started its console driver, so a large screen often shows
a small block of text. -fill fixes that, but the screen resolution goes
back to the firmware default and the consoles are disconnected for a
moment (on a serial console you may lose some output). To keep a chosen
resolution instead, gop -fit lowers it until the text fills the screen.
Example: mode -fill
gop-data
Show or change the screen resolution (graphics modes)
gop [MODE | WIDTH HEIGHT | -max | -fit]
(none) list the modes (number, resolution, pixel format), then
the frame buffer address and size
WIDTH HEIGHT switch to the mode with this resolution
MODE switch to this mode number, as listed
-max switch to the largest resolution available
-fit smallest resolution that still holds the text console,
so the text fills the screen
gop 1024 768 a common resolution
The text console keeps its own size (see mode): the firmware draws
characters in cells of 8 x 19 pixels, so a large screen may show the
text in a corner. A text mode too large for the new resolution is
changed first. With -data: mode, width, height, format, current (one
record per mode), then framebuffer, framebuffer_size.
sermode
Show or set serial port settings (parity n|e|o|m|s, stop bits 0|1|1.5|2)
sermode [HANDLE [BAUD PARITY DATABITS STOPBITS]]
(none) list all serial ports and settings
HANDLE show one port (handle number, hex)
HANDLE BAUD PARITY DATABITS STOP change the settings of a port
PARITY d (default), n, e, o, m or s (only the first letter counts)
DATABITS 5 to 8; STOP 0 (default), 1, 1.5 (or 15) or 2
The receive FIFO depth and timeout are kept. Handles are shown by dh.
Example: sermode 5C 115200 n 8 1
loadpcirom
Load the UEFI drivers contained in a PCI option ROM file
loadpcirom [-nc] ROMFILE...
ROMFILE PCI option ROM image file; several files may be given
-nc load and start the drivers but do not connect them
Every x64 UEFI image in the ROM is loaded and started (compressed images
are expanded first); legacy and other-architecture images are skipped.
Then all controllers are connected, unless -nc is given.
With Secure Boot active, the firmware checks the driver signatures.
Example: loadpcirom -nc nic.rom
Show or set the IPv4 configuration of the network interfaces
ifconfig [-l [NAME]] | -r [NAME] | -s NAME dhcp | -s NAME static IP MASK GW | -s NAME dns IP...
ifconfig -l [NAME] list the interfaces (eth0...) and their settings
ifconfig -s eth0 dhcp get an address with DHCP (waits up to 15 s)
ifconfig -s eth0 static 192.168.1.10 255.255.255.0 192.168.1.1
fixed address, mask and gateway
ifconfig -s eth0 dns 192.168.1.1 DNS servers
ifconfig -r [NAME] reset to DHCP
The firmware network drivers must be loaded (network boot enabled in the
setup, or: load MnpDxe.efi ArpDxe.efi Ip4Dxe.efi Udp4Dxe.efi Dhcp4Dxe.efi
Mtftp4Dxe.efi TcpDxe.efi ...). See also ifconfig6 for IPv6.
With -data (ifconfig -l -data): name, media, policy, mac, ip, mask,
gateway, dns.
ifconfig6-data
Show or set the IPv6 configuration of the network interfaces
ifconfig6 [-l [NAME]] | -r [NAME] | -s NAME auto | -s NAME man [host ADDR[/LEN]...] [gw ADDR...] [dns ADDR...] | -s NAME dad COUNT
ifconfig6 -l [NAME] list the interfaces and their IPv6 settings
ifconfig6 -s eth0 auto automatic configuration (router advertisements)
ifconfig6 -s eth0 man host 2001:db8::10/64 gw 2001:db8::1 dns 2001:db8::53
manual configuration (prefix length 64 if
omitted)
ifconfig6 -s eth0 dad 1 duplicate address detection messages per address
ifconfig6 -r [NAME] reset to automatic configuration
A link-local address (fe80::...) is always present. ping, tftp and http
accept IPv6 addresses; in URLs they go in brackets: http://[2001:db8::1]/f.
The firmware IPv6 drivers must be loaded (IPv6 network boot enabled in the
setup, or: load MnpDxe.efi Ip6Dxe.efi Udp6Dxe.efi Dhcp6Dxe.efi
Mtftp6Dxe.efi TcpDxe.efi).
With -data (ifconfig6 -l -data): name, media, policy, mac, ip (ADDR/LEN
list), gateway, dns, dad.
ping
Send echo requests to an IPv4 or IPv6 address
ping [-n COUNT] [-l SIZE] [-i IF] ADDRESS
ping 192.168.1.1 IPv4
ping -n 3 2001:db8::1 IPv6 (same as ping6)
Ends with an error (ERR <> 0) when no answer arrives.
ping6
Send echo requests to an IPv6 address (ping accepts IPv6 too)
-n COUNT number of requests (default 10)
-l SIZE data bytes per request (0-1400, default 16)
-s SOURCE source address (default: one that can reach ADDRESS)
-i IF interface name (default: the first one)
ping6 -n 3 fe80::1 link-local address: the link-local source is used
Ends with an error (ERR <> 0) when no answer arrives. Without an address
other than link-local, run 'ifconfig6 -s eth0 auto' first.
Full-screen hex editor for files, disk blocks or memory
edit
Full-screen text editor (UTF-8 or UCS-2 files; Ctrl-E for help)
edit FILE
edit FILE open FILE; a new FILE is created when you save
Keys (Ctrl-E shows them inside the editor):
F1 Ctrl-G go to line F6 Ctrl-K cut the current line
F2 Ctrl-S save F7 Ctrl-U paste the cut lines
F3 Ctrl-Q exit (also Esc) F8 Ctrl-O open another file
F4 Ctrl-F find F9 Ctrl-T switch UTF-8 / UCS-2
F5 Ctrl-R find and replace F10 Ctrl-N find next
Find is case-sensitive and wraps around; replace asks y/n/a(ll) per match.
Cut lines in a row form one block; paste inserts the last block cut.
The file keeps its encoding (UTF-8 with or without BOM, or UCS-2) and line
ends (LF or CRLF). Tab characters are kept and shown up to the next multiple
of 4 columns; the Tab key inserts 4 spaces. Needs an interactive console.
hexedit
Full-screen hex editor for files, disk blocks or memory
-d DEVICE LBA COUNT disk blocks (DEVICE: blkN, fsN: or a handle;
numbers in hex)
-m ADDRESS SIZE memory (writing is disabled while Secure Boot
is active)
Keys: arrows, PgUp/PgDn, Tab switches hex/ASCII, F1 go to, F2 save, F3 exit.
Index
Commands, BASIC functions and topics in alphabetical order. The number after each entry is the section.