grub: Shell-like scripting
6.3 Writing full configuration files directly
=============================================
'grub.cfg' is written in GRUB's built-in scripting language, which has a
syntax quite similar to that of GNU Bash and other Bourne shell
derivatives.
Words
=====
A "word" is a sequence of characters considered as a single unit by
GRUB. Words are separated by "metacharacters", which are the following
plus space, tab, and newline:
{ } | & $ ; < >
Quoting may be used to include metacharacters in words; see below.
Reserved words
==============
Reserved words have a special meaning to GRUB. The following words are
recognised as reserved when unquoted and either the first word of a
simple command or the third word of a 'for' command:
! [[ ]] { }
case do done elif else esac fi for function
if in menuentry select then time until while
Not all of these reserved words have a useful purpose yet; some are
reserved for future expansion.
Quoting
=======
Quoting is used to remove the special meaning of certain characters or
words. It can be used to treat metacharacters as part of a word, to
prevent reserved words from being recognised as such, and to prevent
variable expansion.
There are three quoting mechanisms: the escape character, single
quotes, and double quotes.
A non-quoted backslash (\) is the "escape character". It preserves
the literal value of the next character that follows, with the exception
of newline.
Enclosing characters in single quotes preserves the literal value of
each character within the quotes. A single quote may not occur between
single quotes, even when preceded by a backslash.
Enclosing characters in double quotes preserves the literal value of
all characters within the quotes, with the exception of '$' and '\'.
The '$' character retains its special meaning within double quotes. The
backslash retains its special meaning only when followed by one of the
following characters: '$', '"', '\', or newline. A backslash-newline
pair is treated as a line continuation (that is, it is removed from the
input stream and effectively ignored(1) (⇒Shell-like
scripting-Footnote-1)). A double quote may be quoted within double
quotes by preceding it with a backslash.
Variable expansion
==================
The '$' character introduces variable expansion. The variable name to
be expanded may be enclosed in braces, which are optional but serve to
protect the variable to be expanded from characters immediately
following it which could be interpreted as part of the name.
Normal variable names begin with an alphabetic character, followed by
zero or more alphanumeric characters. These names refer to entries in
the GRUB environment (⇒Environment).
Positional variable names consist of one or more digits. They
represent parameters passed to function calls, with '$1' representing
the first parameter, and so on.
The special variable name '?' expands to the exit status of the most
recently executed command. When positional variable names are active,
other special variable names '@', '*' and '#' are defined and they
expand to all positional parameters with necessary quoting, positional
parameters without any quoting, and positional parameter count
respectively.
Comments
========
A word beginning with '#' causes that word and all remaining characters
on that line to be ignored.
Simple commands
===============
A "simple command" is a sequence of words separated by spaces or tabs
and terminated by a semicolon or a newline. The first word specifies
the command to be executed. The remaining words are passed as arguments
to the invoked command.
The return value of a simple command is its exit status. If the
reserved word '!' precedes the command, then the return value is instead
the logical negation of the command's exit status.
Compound commands
=================
A "compound command" is one of the following:
for NAME in WORD ...; do LIST; done
The list of words following 'in' is expanded, generating a list of
items. The variable NAME is set to each element of this list in
turn, and LIST is executed each time. The return value is the exit
status of the last command that executes. If the expansion of the
items following 'in' results in an empty list, no commands are
executed, and the return status is 0.
if LIST; then LIST; [elif LIST; then LIST;] ... [else LIST;] fi
The 'if' LIST is executed. If its exit status is zero, the 'then'
LIST is executed. Otherwise, each 'elif' LIST is executed in turn,
and if its exit status is zero, the corresponding 'then' LIST is
executed and the command completes. Otherwise, the 'else' LIST is
executed, if present. The exit status is the exit status of the
last command executed, or zero if no condition tested true.
while COND; do LIST; done
until COND; do LIST; done
The 'while' command continuously executes the 'do' LIST as long as
the last command in COND returns an exit status of zero. The
'until' command is identical to the 'while' command, except that
the test is negated; the 'do' LIST is executed as long as the last
command in COND returns a non-zero exit status. The exit status of
the 'while' and 'until' commands is the exit status of the last
'do' LIST command executed, or zero if none was executed.
function NAME { COMMAND; ... }
This defines a function named NAME. The "body" of the function is
the list of commands within braces, each of which must be
terminated with a semicolon or a newline. This list of commands
will be executed whenever NAME is specified as the name of a simple
command. Function definitions do not affect the exit status in
'$?'. When executed, the exit status of a function is the exit
status of the last command executed in the body.
menuentry TITLE ['--class=class' ...] ['--users=users'] ['--unrestricted'] ['--hotkey=key'] ['--id=id'] { COMMAND; ... }
⇒menuentry.
Built-in Commands
=================
Some built-in commands are also provided by GRUB script to help script
writers perform actions that are otherwise not possible. For example,
these include commands to jump out of a loop without fully completing
it, etc.
break ['n']
Exit from within a 'for', 'while', or 'until' loop. If 'n' is
specified, break 'n' levels. 'n' must be greater than or equal to
1. If 'n' is greater than the number of enclosing loops, all
enclosing loops are exited. The return value is 0 unless 'n' is
not greater than or equal to 1.
continue ['n']
Resume the next iteration of the enclosing 'for', 'while' or
'until' loop. If 'n' is specified, resume at the 'n'th enclosing
loop. 'n' must be greater than or equal to 1. If 'n' is greater
than the number of enclosing loops, the last enclosing loop (the
"top-level" loop) is resumed. The return value is 0 unless 'n' is
not greater than or equal to 1.
return ['n']
Causes a function to exit with the return value specified by 'n'.
If 'n' is omitted, the return status is that of the last command
executed in the function body. If used outside a function the
return status is false.
setparams ['arg'] ...
Replace positional parameters starting with '$1' with arguments to
'setparams'.
shift ['n']
The positional parameters from 'n'+1 ... are renamed to '$1'....
Parameters represented by the numbers '$#' down to '$#'-'n'+1 are
unset. 'n' must be a non-negative number less than or equal to
'$#'. If 'n' is 0, no parameters are changed. If 'n' is not
given, it is assumed to be 1. If 'n' is greater than '$#', the
positional parameters are not changed. The return status is
greater than zero if 'n' is greater than '$#' or less than zero;
otherwise 0.