9

Creating custom menu entry, got stuck on this command:

exec tail -n +3 $0

Tried it in terminal, got weird result, cannot understand, what this command exactly does and why grub needs it. Could you explain, please?

muru
  • 72,889
Imajou
  • 93

2 Answers2

12

If you're talking about /etc/grub.d/40_custom:

$ cat /etc/grub.d/40_custom
#!/bin/sh
exec tail -n +3 $0
# This file provides an easy way to add custom menu entries.  Simply type the
# menu entries you want to add after this comment.  Be careful not to change
# the 'exec tail' line above.

Then note that:

  • this is a shell script, and is executed by grub-mkconfig to build GRUB configuration
  • this file is supposed to be "an easy way to add custom menu entries" - you just type in exactly whatever GRUB configuration you want.

But this is a shell script, so usually you'd have to do something like echo "menuentry ...." etc. To avoid that, the exec tail magic is used. What does that do? $0, remember, is the name of the script as executed, so typically it would be 40_custom (or /etc/grub.d/40_custom, etc. depending on where and how it was run). So the script is essentially running tail on itself, but with -n +3, which tells tail to start from the third line.

What do you get if you output everything from the third line onwards in /etc/grub.d/40_custom?

# This file provides an easy way to add custom menu entries.  Simply type the
# menu entries you want to add after this comment.  Be careful not to change
# the 'exec tail' line above.

(And additionally whatever else you put below this.)

The exec part replaces the shell that's executing the script with tail, so effectively nothing further from the script is executed.


Running it in the terminal:

  • $0 is probably bash or something like that (it could be /bin/bash)
  • and because of the exec, you're replacing the running shell with tail -n+3 bash
  • and since you probably don't have a file named bash in your current directory, tail promptly quits.

So the end result is likely that your terminal session ended there.

muru
  • 72,889
10

tail -n +3 prints its input, starting at line 3 (man page). $0 is the name of the script in a shell script (Bash special parameters) and exec (Bash builtins) replaces the script with the command. You probably have something like this (like in /etc/grub.d/40_custom on my system):

#!/bin/sh
exec tail -n +3 $0
foo
bar

When you run the script, it replaces itself with tail reading the script itself, so the rest of the script gets copied to its output.

I think grub has a bunch of scripts to create its config, they're probably executed as grubscript.sh >> grub-config-file or something to effect. The scripts could use any logic they need to produce the output, but the exec tail trick allows to just dump some fixed lines in the output without changing the logic the script is started with.

In addition to that magic incantation, Debian's /etc/grub.d/40_custom also includes a comment telling the user to

Simply type the menu entries you want to add after this comment.

ilkkachu
  • 138,973
  • FWIW, squinting hard and assuming # is a comment character for grub anway, #!/bin/cat should work, too. (You'll have the shebang comment line in the output, though.) – Ulrich Schwarz Jan 07 '19 at 14:06