Scripting Features

The features mentioned here are NOT YET part of mainline gPXE, and are still under development. The modified code can be found in my git repository, in the expt branch.

  1. Identifiers
  2. Arithmetic evaluator
  3. Quoting
  4. Branches
  5. Return code
  6. Loops

Identifiers

See the Identifiers section at: http://etherboot.org/wiki/commandline, for the basic syntax of an identifier. The new code allows identifiers to be 'nested', like:

set i 0
echo ${net${i}/ip}

will print the IP address of the net0 interface. Arithmetic operations (see 2) can also be performed within the ${}: E.g.:

set i 0
echo ${net$(${i}+1)/ip}

will print the IP address of the net1 interface (if it exists).

Arithmetic Evaluation

Arithmetic expressions can be evaluated by placing them within $(). The following operators are supported (in order of decreasing precedence):

  1. !, ~ (logical NOT and bitwise negation)
  2. *, /, % (multiplication, division, and modulo)
  3. +, - (addition, subtraction)
  4. «, » (left- and right-shift)
  5. <, ⇐, >, >= (inequality)
  6. !=, == (equal, not equal)
  7. & (bitwise AND)
  8. | (bitwise OR)
  9. ^ (bitwise EX-OR)
  10. && (logical AND)
  11. || (logical OR)

The == and != operators also act on strings. Identifiers are expanded by placing them within ${}. E.g.:

echo $(1 + 2)
set a 15
echo $(${a} * 3 + 5)
echo $( ${net0/ip} != "" )

Output:

3
50
1

Quoting

The \ is used as an escape character. The following sequences are recognised:

  • \<space> Treats the space as part of the command-line argument
  • \<tab> Ditto
  • \<newline> Concatenates the next line to the current line. Both the \ and the newline character are removed
  • \<any other character> Removes the special meaning of the character (if any)

Within single-quotes, all characters lose their special meaning. Within double-quotes, the \ and $ retain their special meaning. Single- and double-quotes allow you to use a newline character in a command-line argument. E.g.:

set message "Hello World"
echo '${message} = '${message}
set message Hello\ \ World
echo ${message}
set message Hello\ World\ \#1	#'Hello World #1' is treated as a single argument
echo ${message}
echo 'Hello
World'  # Will introduce a newline between Hello and World
echo Hello \
World
echo It\'s good to see you!

Output:

${message} = Hello World
Hello  World
Hello World #1
Hello
World
Hello World
It's good to see you!

Branches

The keywords if, else and fi are used to branch command execution:

if <condition>
    <statements>
fi
if <condition>
    <statements>
else		#optional
    <statements>
fi

A try-catch block is a special kind of branch.

try
    <crucial statements>	#Call this statment sequence A
catch
    <backup statements>	#Call this statement sequence B
done

The statements in sequence A are executed one by one. If any of them fails, execution branches immediately to sequence B. If all the statements in sequence A are executed successfully, execution skips sequence B, and continue after the done statement.

E.g.:

if $( ${filename} != "" && ${server} != "")
	chain tftp://${server}//${filename}
else
	echo "No filename"
fi

will first check that neither filename and server are not empty, before attempting to boot. If either is empty, display an error message.

try
	kernel tftp://${server}//${kernel}
	initrd tftp://${server}//${initrd}
	boot
catch
	echo "Oops: ${rc}"
done

will attempt to boot using the given kernel and initrd. If any of the three commands fail, it displays a message.

Return Code

The return code of the previous statement can be checked using the ${rc} variable. A value of 0 means that the command completed successfully, while any other value means the command was not successful.

E.g.:

dhcp net0
if $( ${rc} != 0 )
    echo "DHCP failed"
else
    chain http://etherboot.org/gtest/gtest.gpxe # (Tom's Root Boot disk)
fi

Loops

You can use while and for loops as:

while <condition>
do
	<statements>
done

The while loop executes the statement block while the condition is true.

for <variable> in <value list>
do
	<statements>
done

The variable takes on each value in the value list one by one.

E.g.:

set i 0
while $( ${net${i}/mac} != "" )
do
	dhcp net${i}
	if $(${rc} == 0)
		chain tftp://${server}//${filename}
	fi
	set i $( ${i} + 1 )
done

will attempt to get a dhcp connection on each valid interface, and if it is successful, boot using a given file.

for i in 0 1 2 3 5 $(6*3)
do
      echo 'i =' ${i}
done

displays:

i = 0
i = 1
i = 2
i = 3
i = 5
i = 18

A break statement will exit a loop, and a continue statement will start the next iteration of the loop.

for i in 1 2 3 4 5 6
do
      if $(${i} == 3)
            continue
      fi
      echo 'i =' ${i}
      if $(${i} == 4)
            break      #This will exit the for loop, not just the if branch
      fi
done

displays:

i = 1
i = 2
i = 4

QR Code
QR Code soc:2009:lynusvaz:notes:scripting_doc:features_added (generated for current page)