Meaning of “exec tail -n +3 $0” line in 40_custom file












14














I am trying to understand the grub config files. So, during this process I came across with file /etc/grub.d/40_custom. My file contains the following lines:



#!/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.
menuentry "Windows 10" --class windows --class os {
insmod part_msdos
savedefault
insmod ntfs
insmod ntldr
set root='(hd0,msdos1)'
ntldr ($root)/bootmgr
}


as my system is dual boot and apparently this is the boot loader for windows 10.



My question though is this part exec tail -n +3 $0.

If I am deciphering it correctly this just means print the last lines starting from the 3rd line (+3) of the file $0. $0 of course in this case is the actual file /etc/grub.d/40_custom.



So, why do we use this command in 40_custom file? As I get it the output would be the same if ιt was omitted altogether. The only different I might think of is the 1st line which identifies the interpreter:



#!/bin/sh


But then again it is executed since exec tail -n +3 $0 follows it. So, is this just a (useless) convention?










share|improve this question



























    14














    I am trying to understand the grub config files. So, during this process I came across with file /etc/grub.d/40_custom. My file contains the following lines:



    #!/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.
    menuentry "Windows 10" --class windows --class os {
    insmod part_msdos
    savedefault
    insmod ntfs
    insmod ntldr
    set root='(hd0,msdos1)'
    ntldr ($root)/bootmgr
    }


    as my system is dual boot and apparently this is the boot loader for windows 10.



    My question though is this part exec tail -n +3 $0.

    If I am deciphering it correctly this just means print the last lines starting from the 3rd line (+3) of the file $0. $0 of course in this case is the actual file /etc/grub.d/40_custom.



    So, why do we use this command in 40_custom file? As I get it the output would be the same if ιt was omitted altogether. The only different I might think of is the 1st line which identifies the interpreter:



    #!/bin/sh


    But then again it is executed since exec tail -n +3 $0 follows it. So, is this just a (useless) convention?










    share|improve this question

























      14












      14








      14







      I am trying to understand the grub config files. So, during this process I came across with file /etc/grub.d/40_custom. My file contains the following lines:



      #!/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.
      menuentry "Windows 10" --class windows --class os {
      insmod part_msdos
      savedefault
      insmod ntfs
      insmod ntldr
      set root='(hd0,msdos1)'
      ntldr ($root)/bootmgr
      }


      as my system is dual boot and apparently this is the boot loader for windows 10.



      My question though is this part exec tail -n +3 $0.

      If I am deciphering it correctly this just means print the last lines starting from the 3rd line (+3) of the file $0. $0 of course in this case is the actual file /etc/grub.d/40_custom.



      So, why do we use this command in 40_custom file? As I get it the output would be the same if ιt was omitted altogether. The only different I might think of is the 1st line which identifies the interpreter:



      #!/bin/sh


      But then again it is executed since exec tail -n +3 $0 follows it. So, is this just a (useless) convention?










      share|improve this question













      I am trying to understand the grub config files. So, during this process I came across with file /etc/grub.d/40_custom. My file contains the following lines:



      #!/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.
      menuentry "Windows 10" --class windows --class os {
      insmod part_msdos
      savedefault
      insmod ntfs
      insmod ntldr
      set root='(hd0,msdos1)'
      ntldr ($root)/bootmgr
      }


      as my system is dual boot and apparently this is the boot loader for windows 10.



      My question though is this part exec tail -n +3 $0.

      If I am deciphering it correctly this just means print the last lines starting from the 3rd line (+3) of the file $0. $0 of course in this case is the actual file /etc/grub.d/40_custom.



      So, why do we use this command in 40_custom file? As I get it the output would be the same if ιt was omitted altogether. The only different I might think of is the 1st line which identifies the interpreter:



      #!/bin/sh


      But then again it is executed since exec tail -n +3 $0 follows it. So, is this just a (useless) convention?







      grub2






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked yesterday









      EyprosEypros

      1838




      1838






















          3 Answers
          3






          active

          oldest

          votes


















          13














          The trick is what exec does:



          $ help exec
          exec: exec [-cl] [-a name] [command [arguments ...]] [redirection ...]
          Replace the shell with the given command.

          Execute COMMAND, replacing this shell with the specified program.
          ARGUMENTS become the arguments to COMMAND. If COMMAND is not specified,
          any redirections take effect in the current shell.


          This means it will replace the shell with whatever is given to exec, in this case tail. Here's an example of it in action:



          $ cat ~/foo.sh
          #!/bin/sh
          exec tail -n +3 "$0"
          echo foo

          $ ./foo.sh
          echo foo


          So the echo command isn't executed since we have changed the shell and are using tail instead. If we remove the exec tail:



          $ cat ~/foo.sh
          #!/bin/sh
          echo foo
          $ ./foo.sh
          foo


          So, this is a neat trick that lets you write a script whose only job is to output its own contents. Presumably, whatever calls 40_custom expects its contents as output. Of course, this begs the question of why not just running tail -n +3 /etc/grub.d/40_custom directly.



          I am guessing the answer is because grub uses its own scripting language and this makes it need this workaround.






          share|improve this answer























          • Nice answer! But what if we'll write #!/bin/tail -n +2 as a shellbang? Will it print rest of the file?
            – val
            yesterday










          • @val try it and see :) Turns out it doesn't work perfectly as a shebang, the -n +2 seems to be interpreted as -n 2 and only the last two lines are printed. That's probably worth its own question though.
            – terdon
            yesterday






          • 3




            @val ...shebang behavior is a lot less standardized and portable than you may expect. See the "interpretation of the command arguments" section of en.wikipedia.org/wiki/Shebang_(Unix)#Portability
            – Charles Duffy
            yesterday












          • @val That works in Linux if you remove the space between the n and the +. In Linux at least, after the executable path and a space, the following characters are treated as a single argument. So with the space, tail sees it and probably decides to remove whatever invalid prefix -n's argument has (in this case, a space and a +) until it gets to the number. However, like Charles Duffy said, the current way they did this is probably more portable to other Unices.
            – JoL
            22 hours ago












          • Why can't this just use a heredoc? Or a cat hashbang?
            – fluffy
            17 hours ago



















          8














          The directory /etc/grub.d/ contains many executables (typically shell scripts, but any other executable type is also possible). Whenever grub-mkconfig gets executed (e.g. if you run update-grub, but also when you install an updated kernel package, which usually has a post-install hook that tells the package manager to update grub.cfg), they are all executed in alphabetical order. Their outputs all get concatenated, and end up in the file /boot/grub/grub.cfg, with neat section headers that show which part comes from which /etc/grub.d/ file.



          This one particular file 40_custom is designed to allow you to easily add entries/lines into grub.cfg by simply typing/pasting them into this file. Other scripts in the same directory do more complex tasks like looking for kernels or non-linux operating systems and creating menu entries for them.



          In order to allow grub-mkconfig to treat all those files in the same way (execute and take the output), 40_custom is a script and uses this exec tail -n +3 $0 mechanism to output its contents (minus the "header"). If it weren't an executable, update-grub would need a special hard-coded exception to take this file's literal text content instead of executing it like all the others. But then what if you (or the makers of another linux distribution) want to give this file a different name? Or what if you didn't know about the exception and created a shell script named 40_custom?



          You can read more about grub-mkconfig and /etc/grub.d/* in the GNU GRUB Manual (although it talks mostly about options you can set in /etc/default/grub), and there should also be a file /etc/grub.d/README that states that these files get executed to form grub.cfg.






          share|improve this answer










          New contributor




          Hans-Jakob is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
          Check out our Code of Conduct.














          • 1




            While terdon's answer explains how the line works, this one gives a more plausible design reason as for why GRUB does things this way.
            – JoL
            21 hours ago










          • Great answer. To your point about special exceptions - a "simpler" exception could have been having two directories e.g. /etc/grub.d/exec for exectuable files/scripts, and /etc/grub.d/static for plain text files, or some other indicator to distinguish these. However, this was the design decision that they went with.
            – Stobor
            14 hours ago



















          3














          TL;DR: it's a trick to simplify adding new entries to the file



          The whole point is described in one of the Ubuntu's Wiki pages on grub:





          1. Only executable files generate output to grub.cfg during execution of update-grub.




          Output of scripts in /etc/grub.d/ becomes the contents of grub.cfg file.



          Now, what does exec do ? It can either re-wire output for entire script or if a command is provided - the mentioned command overtakes and replaces the script process. What was once shell script with PID 1234 now is tail command with PID 1234.



          Now you already know that tail -n +3 $0 prints everything after the 3rd line in the script itself. So why do we need to do this ? If grub only cares about the output we could just as well do



          cat <<EOF
          menuentry {
          ...
          }
          EOF


          In fact, you will find cat <<EOF example in Fedora documentation, albeit for a different purpose. The whole point is in the comments - ease of use for the users:



          # This file provides an easy way to add custom menu entries.  Simply type the
          # menu entries you want to add after this comment.


          With exec trick, you don't have to know what does cat <<EOF do (spoiler, that's called here-doc), nor you have to remember to add the EOF on the last line. Just add menuentry to the file and be done with it. Plus, if you're scripting adding a menuentry, you can simply append via >> in shell to this file.



          See also:




          • What logic does the command “exec tail -n +3 $0” from grub2 config have?






          share|improve this answer























          • But why not have grub read the files directly? Do you have any idea why they chose to make them executable instead? It would be much simpler to have them as simple text files which are read by whatever process generates the menu, but instead they chose to make them executable and added this (neat) but complex workaround. Is it because grub has its own scripting language as I posit in my answer?
            – terdon
            yesterday










          • @terdon I don't think this has to do anything with the grub language itself. You wouldn't need #!/bin/sh in that case. I suspect this is simply historical reason (carried over from PUPA codebase ) and a design decision inspired by SysV type of scripting.
            – Sergiy Kolodyazhnyy
            yesterday










          • @terdon This actually inspired a question: unix.stackexchange.com/q/492966/85039
            – Sergiy Kolodyazhnyy
            yesterday











          Your Answer








          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "89"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2faskubuntu.com%2fquestions%2f1107668%2fmeaning-of-exec-tail-n-3-0-line-in-40-custom-file%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          3 Answers
          3






          active

          oldest

          votes








          3 Answers
          3






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          13














          The trick is what exec does:



          $ help exec
          exec: exec [-cl] [-a name] [command [arguments ...]] [redirection ...]
          Replace the shell with the given command.

          Execute COMMAND, replacing this shell with the specified program.
          ARGUMENTS become the arguments to COMMAND. If COMMAND is not specified,
          any redirections take effect in the current shell.


          This means it will replace the shell with whatever is given to exec, in this case tail. Here's an example of it in action:



          $ cat ~/foo.sh
          #!/bin/sh
          exec tail -n +3 "$0"
          echo foo

          $ ./foo.sh
          echo foo


          So the echo command isn't executed since we have changed the shell and are using tail instead. If we remove the exec tail:



          $ cat ~/foo.sh
          #!/bin/sh
          echo foo
          $ ./foo.sh
          foo


          So, this is a neat trick that lets you write a script whose only job is to output its own contents. Presumably, whatever calls 40_custom expects its contents as output. Of course, this begs the question of why not just running tail -n +3 /etc/grub.d/40_custom directly.



          I am guessing the answer is because grub uses its own scripting language and this makes it need this workaround.






          share|improve this answer























          • Nice answer! But what if we'll write #!/bin/tail -n +2 as a shellbang? Will it print rest of the file?
            – val
            yesterday










          • @val try it and see :) Turns out it doesn't work perfectly as a shebang, the -n +2 seems to be interpreted as -n 2 and only the last two lines are printed. That's probably worth its own question though.
            – terdon
            yesterday






          • 3




            @val ...shebang behavior is a lot less standardized and portable than you may expect. See the "interpretation of the command arguments" section of en.wikipedia.org/wiki/Shebang_(Unix)#Portability
            – Charles Duffy
            yesterday












          • @val That works in Linux if you remove the space between the n and the +. In Linux at least, after the executable path and a space, the following characters are treated as a single argument. So with the space, tail sees it and probably decides to remove whatever invalid prefix -n's argument has (in this case, a space and a +) until it gets to the number. However, like Charles Duffy said, the current way they did this is probably more portable to other Unices.
            – JoL
            22 hours ago












          • Why can't this just use a heredoc? Or a cat hashbang?
            – fluffy
            17 hours ago
















          13














          The trick is what exec does:



          $ help exec
          exec: exec [-cl] [-a name] [command [arguments ...]] [redirection ...]
          Replace the shell with the given command.

          Execute COMMAND, replacing this shell with the specified program.
          ARGUMENTS become the arguments to COMMAND. If COMMAND is not specified,
          any redirections take effect in the current shell.


          This means it will replace the shell with whatever is given to exec, in this case tail. Here's an example of it in action:



          $ cat ~/foo.sh
          #!/bin/sh
          exec tail -n +3 "$0"
          echo foo

          $ ./foo.sh
          echo foo


          So the echo command isn't executed since we have changed the shell and are using tail instead. If we remove the exec tail:



          $ cat ~/foo.sh
          #!/bin/sh
          echo foo
          $ ./foo.sh
          foo


          So, this is a neat trick that lets you write a script whose only job is to output its own contents. Presumably, whatever calls 40_custom expects its contents as output. Of course, this begs the question of why not just running tail -n +3 /etc/grub.d/40_custom directly.



          I am guessing the answer is because grub uses its own scripting language and this makes it need this workaround.






          share|improve this answer























          • Nice answer! But what if we'll write #!/bin/tail -n +2 as a shellbang? Will it print rest of the file?
            – val
            yesterday










          • @val try it and see :) Turns out it doesn't work perfectly as a shebang, the -n +2 seems to be interpreted as -n 2 and only the last two lines are printed. That's probably worth its own question though.
            – terdon
            yesterday






          • 3




            @val ...shebang behavior is a lot less standardized and portable than you may expect. See the "interpretation of the command arguments" section of en.wikipedia.org/wiki/Shebang_(Unix)#Portability
            – Charles Duffy
            yesterday












          • @val That works in Linux if you remove the space between the n and the +. In Linux at least, after the executable path and a space, the following characters are treated as a single argument. So with the space, tail sees it and probably decides to remove whatever invalid prefix -n's argument has (in this case, a space and a +) until it gets to the number. However, like Charles Duffy said, the current way they did this is probably more portable to other Unices.
            – JoL
            22 hours ago












          • Why can't this just use a heredoc? Or a cat hashbang?
            – fluffy
            17 hours ago














          13












          13








          13






          The trick is what exec does:



          $ help exec
          exec: exec [-cl] [-a name] [command [arguments ...]] [redirection ...]
          Replace the shell with the given command.

          Execute COMMAND, replacing this shell with the specified program.
          ARGUMENTS become the arguments to COMMAND. If COMMAND is not specified,
          any redirections take effect in the current shell.


          This means it will replace the shell with whatever is given to exec, in this case tail. Here's an example of it in action:



          $ cat ~/foo.sh
          #!/bin/sh
          exec tail -n +3 "$0"
          echo foo

          $ ./foo.sh
          echo foo


          So the echo command isn't executed since we have changed the shell and are using tail instead. If we remove the exec tail:



          $ cat ~/foo.sh
          #!/bin/sh
          echo foo
          $ ./foo.sh
          foo


          So, this is a neat trick that lets you write a script whose only job is to output its own contents. Presumably, whatever calls 40_custom expects its contents as output. Of course, this begs the question of why not just running tail -n +3 /etc/grub.d/40_custom directly.



          I am guessing the answer is because grub uses its own scripting language and this makes it need this workaround.






          share|improve this answer














          The trick is what exec does:



          $ help exec
          exec: exec [-cl] [-a name] [command [arguments ...]] [redirection ...]
          Replace the shell with the given command.

          Execute COMMAND, replacing this shell with the specified program.
          ARGUMENTS become the arguments to COMMAND. If COMMAND is not specified,
          any redirections take effect in the current shell.


          This means it will replace the shell with whatever is given to exec, in this case tail. Here's an example of it in action:



          $ cat ~/foo.sh
          #!/bin/sh
          exec tail -n +3 "$0"
          echo foo

          $ ./foo.sh
          echo foo


          So the echo command isn't executed since we have changed the shell and are using tail instead. If we remove the exec tail:



          $ cat ~/foo.sh
          #!/bin/sh
          echo foo
          $ ./foo.sh
          foo


          So, this is a neat trick that lets you write a script whose only job is to output its own contents. Presumably, whatever calls 40_custom expects its contents as output. Of course, this begs the question of why not just running tail -n +3 /etc/grub.d/40_custom directly.



          I am guessing the answer is because grub uses its own scripting language and this makes it need this workaround.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited yesterday

























          answered yesterday









          terdonterdon

          64.9k12137217




          64.9k12137217












          • Nice answer! But what if we'll write #!/bin/tail -n +2 as a shellbang? Will it print rest of the file?
            – val
            yesterday










          • @val try it and see :) Turns out it doesn't work perfectly as a shebang, the -n +2 seems to be interpreted as -n 2 and only the last two lines are printed. That's probably worth its own question though.
            – terdon
            yesterday






          • 3




            @val ...shebang behavior is a lot less standardized and portable than you may expect. See the "interpretation of the command arguments" section of en.wikipedia.org/wiki/Shebang_(Unix)#Portability
            – Charles Duffy
            yesterday












          • @val That works in Linux if you remove the space between the n and the +. In Linux at least, after the executable path and a space, the following characters are treated as a single argument. So with the space, tail sees it and probably decides to remove whatever invalid prefix -n's argument has (in this case, a space and a +) until it gets to the number. However, like Charles Duffy said, the current way they did this is probably more portable to other Unices.
            – JoL
            22 hours ago












          • Why can't this just use a heredoc? Or a cat hashbang?
            – fluffy
            17 hours ago


















          • Nice answer! But what if we'll write #!/bin/tail -n +2 as a shellbang? Will it print rest of the file?
            – val
            yesterday










          • @val try it and see :) Turns out it doesn't work perfectly as a shebang, the -n +2 seems to be interpreted as -n 2 and only the last two lines are printed. That's probably worth its own question though.
            – terdon
            yesterday






          • 3




            @val ...shebang behavior is a lot less standardized and portable than you may expect. See the "interpretation of the command arguments" section of en.wikipedia.org/wiki/Shebang_(Unix)#Portability
            – Charles Duffy
            yesterday












          • @val That works in Linux if you remove the space between the n and the +. In Linux at least, after the executable path and a space, the following characters are treated as a single argument. So with the space, tail sees it and probably decides to remove whatever invalid prefix -n's argument has (in this case, a space and a +) until it gets to the number. However, like Charles Duffy said, the current way they did this is probably more portable to other Unices.
            – JoL
            22 hours ago












          • Why can't this just use a heredoc? Or a cat hashbang?
            – fluffy
            17 hours ago
















          Nice answer! But what if we'll write #!/bin/tail -n +2 as a shellbang? Will it print rest of the file?
          – val
          yesterday




          Nice answer! But what if we'll write #!/bin/tail -n +2 as a shellbang? Will it print rest of the file?
          – val
          yesterday












          @val try it and see :) Turns out it doesn't work perfectly as a shebang, the -n +2 seems to be interpreted as -n 2 and only the last two lines are printed. That's probably worth its own question though.
          – terdon
          yesterday




          @val try it and see :) Turns out it doesn't work perfectly as a shebang, the -n +2 seems to be interpreted as -n 2 and only the last two lines are printed. That's probably worth its own question though.
          – terdon
          yesterday




          3




          3




          @val ...shebang behavior is a lot less standardized and portable than you may expect. See the "interpretation of the command arguments" section of en.wikipedia.org/wiki/Shebang_(Unix)#Portability
          – Charles Duffy
          yesterday






          @val ...shebang behavior is a lot less standardized and portable than you may expect. See the "interpretation of the command arguments" section of en.wikipedia.org/wiki/Shebang_(Unix)#Portability
          – Charles Duffy
          yesterday














          @val That works in Linux if you remove the space between the n and the +. In Linux at least, after the executable path and a space, the following characters are treated as a single argument. So with the space, tail sees it and probably decides to remove whatever invalid prefix -n's argument has (in this case, a space and a +) until it gets to the number. However, like Charles Duffy said, the current way they did this is probably more portable to other Unices.
          – JoL
          22 hours ago






          @val That works in Linux if you remove the space between the n and the +. In Linux at least, after the executable path and a space, the following characters are treated as a single argument. So with the space, tail sees it and probably decides to remove whatever invalid prefix -n's argument has (in this case, a space and a +) until it gets to the number. However, like Charles Duffy said, the current way they did this is probably more portable to other Unices.
          – JoL
          22 hours ago














          Why can't this just use a heredoc? Or a cat hashbang?
          – fluffy
          17 hours ago




          Why can't this just use a heredoc? Or a cat hashbang?
          – fluffy
          17 hours ago













          8














          The directory /etc/grub.d/ contains many executables (typically shell scripts, but any other executable type is also possible). Whenever grub-mkconfig gets executed (e.g. if you run update-grub, but also when you install an updated kernel package, which usually has a post-install hook that tells the package manager to update grub.cfg), they are all executed in alphabetical order. Their outputs all get concatenated, and end up in the file /boot/grub/grub.cfg, with neat section headers that show which part comes from which /etc/grub.d/ file.



          This one particular file 40_custom is designed to allow you to easily add entries/lines into grub.cfg by simply typing/pasting them into this file. Other scripts in the same directory do more complex tasks like looking for kernels or non-linux operating systems and creating menu entries for them.



          In order to allow grub-mkconfig to treat all those files in the same way (execute and take the output), 40_custom is a script and uses this exec tail -n +3 $0 mechanism to output its contents (minus the "header"). If it weren't an executable, update-grub would need a special hard-coded exception to take this file's literal text content instead of executing it like all the others. But then what if you (or the makers of another linux distribution) want to give this file a different name? Or what if you didn't know about the exception and created a shell script named 40_custom?



          You can read more about grub-mkconfig and /etc/grub.d/* in the GNU GRUB Manual (although it talks mostly about options you can set in /etc/default/grub), and there should also be a file /etc/grub.d/README that states that these files get executed to form grub.cfg.






          share|improve this answer










          New contributor




          Hans-Jakob is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
          Check out our Code of Conduct.














          • 1




            While terdon's answer explains how the line works, this one gives a more plausible design reason as for why GRUB does things this way.
            – JoL
            21 hours ago










          • Great answer. To your point about special exceptions - a "simpler" exception could have been having two directories e.g. /etc/grub.d/exec for exectuable files/scripts, and /etc/grub.d/static for plain text files, or some other indicator to distinguish these. However, this was the design decision that they went with.
            – Stobor
            14 hours ago
















          8














          The directory /etc/grub.d/ contains many executables (typically shell scripts, but any other executable type is also possible). Whenever grub-mkconfig gets executed (e.g. if you run update-grub, but also when you install an updated kernel package, which usually has a post-install hook that tells the package manager to update grub.cfg), they are all executed in alphabetical order. Their outputs all get concatenated, and end up in the file /boot/grub/grub.cfg, with neat section headers that show which part comes from which /etc/grub.d/ file.



          This one particular file 40_custom is designed to allow you to easily add entries/lines into grub.cfg by simply typing/pasting them into this file. Other scripts in the same directory do more complex tasks like looking for kernels or non-linux operating systems and creating menu entries for them.



          In order to allow grub-mkconfig to treat all those files in the same way (execute and take the output), 40_custom is a script and uses this exec tail -n +3 $0 mechanism to output its contents (minus the "header"). If it weren't an executable, update-grub would need a special hard-coded exception to take this file's literal text content instead of executing it like all the others. But then what if you (or the makers of another linux distribution) want to give this file a different name? Or what if you didn't know about the exception and created a shell script named 40_custom?



          You can read more about grub-mkconfig and /etc/grub.d/* in the GNU GRUB Manual (although it talks mostly about options you can set in /etc/default/grub), and there should also be a file /etc/grub.d/README that states that these files get executed to form grub.cfg.






          share|improve this answer










          New contributor




          Hans-Jakob is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
          Check out our Code of Conduct.














          • 1




            While terdon's answer explains how the line works, this one gives a more plausible design reason as for why GRUB does things this way.
            – JoL
            21 hours ago










          • Great answer. To your point about special exceptions - a "simpler" exception could have been having two directories e.g. /etc/grub.d/exec for exectuable files/scripts, and /etc/grub.d/static for plain text files, or some other indicator to distinguish these. However, this was the design decision that they went with.
            – Stobor
            14 hours ago














          8












          8








          8






          The directory /etc/grub.d/ contains many executables (typically shell scripts, but any other executable type is also possible). Whenever grub-mkconfig gets executed (e.g. if you run update-grub, but also when you install an updated kernel package, which usually has a post-install hook that tells the package manager to update grub.cfg), they are all executed in alphabetical order. Their outputs all get concatenated, and end up in the file /boot/grub/grub.cfg, with neat section headers that show which part comes from which /etc/grub.d/ file.



          This one particular file 40_custom is designed to allow you to easily add entries/lines into grub.cfg by simply typing/pasting them into this file. Other scripts in the same directory do more complex tasks like looking for kernels or non-linux operating systems and creating menu entries for them.



          In order to allow grub-mkconfig to treat all those files in the same way (execute and take the output), 40_custom is a script and uses this exec tail -n +3 $0 mechanism to output its contents (minus the "header"). If it weren't an executable, update-grub would need a special hard-coded exception to take this file's literal text content instead of executing it like all the others. But then what if you (or the makers of another linux distribution) want to give this file a different name? Or what if you didn't know about the exception and created a shell script named 40_custom?



          You can read more about grub-mkconfig and /etc/grub.d/* in the GNU GRUB Manual (although it talks mostly about options you can set in /etc/default/grub), and there should also be a file /etc/grub.d/README that states that these files get executed to form grub.cfg.






          share|improve this answer










          New contributor




          Hans-Jakob is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
          Check out our Code of Conduct.









          The directory /etc/grub.d/ contains many executables (typically shell scripts, but any other executable type is also possible). Whenever grub-mkconfig gets executed (e.g. if you run update-grub, but also when you install an updated kernel package, which usually has a post-install hook that tells the package manager to update grub.cfg), they are all executed in alphabetical order. Their outputs all get concatenated, and end up in the file /boot/grub/grub.cfg, with neat section headers that show which part comes from which /etc/grub.d/ file.



          This one particular file 40_custom is designed to allow you to easily add entries/lines into grub.cfg by simply typing/pasting them into this file. Other scripts in the same directory do more complex tasks like looking for kernels or non-linux operating systems and creating menu entries for them.



          In order to allow grub-mkconfig to treat all those files in the same way (execute and take the output), 40_custom is a script and uses this exec tail -n +3 $0 mechanism to output its contents (minus the "header"). If it weren't an executable, update-grub would need a special hard-coded exception to take this file's literal text content instead of executing it like all the others. But then what if you (or the makers of another linux distribution) want to give this file a different name? Or what if you didn't know about the exception and created a shell script named 40_custom?



          You can read more about grub-mkconfig and /etc/grub.d/* in the GNU GRUB Manual (although it talks mostly about options you can set in /etc/default/grub), and there should also be a file /etc/grub.d/README that states that these files get executed to form grub.cfg.







          share|improve this answer










          New contributor




          Hans-Jakob is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
          Check out our Code of Conduct.









          share|improve this answer



          share|improve this answer








          edited yesterday





















          New contributor




          Hans-Jakob is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
          Check out our Code of Conduct.









          answered yesterday









          Hans-JakobHans-Jakob

          812




          812




          New contributor




          Hans-Jakob is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
          Check out our Code of Conduct.





          New contributor





          Hans-Jakob is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
          Check out our Code of Conduct.






          Hans-Jakob is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
          Check out our Code of Conduct.








          • 1




            While terdon's answer explains how the line works, this one gives a more plausible design reason as for why GRUB does things this way.
            – JoL
            21 hours ago










          • Great answer. To your point about special exceptions - a "simpler" exception could have been having two directories e.g. /etc/grub.d/exec for exectuable files/scripts, and /etc/grub.d/static for plain text files, or some other indicator to distinguish these. However, this was the design decision that they went with.
            – Stobor
            14 hours ago














          • 1




            While terdon's answer explains how the line works, this one gives a more plausible design reason as for why GRUB does things this way.
            – JoL
            21 hours ago










          • Great answer. To your point about special exceptions - a "simpler" exception could have been having two directories e.g. /etc/grub.d/exec for exectuable files/scripts, and /etc/grub.d/static for plain text files, or some other indicator to distinguish these. However, this was the design decision that they went with.
            – Stobor
            14 hours ago








          1




          1




          While terdon's answer explains how the line works, this one gives a more plausible design reason as for why GRUB does things this way.
          – JoL
          21 hours ago




          While terdon's answer explains how the line works, this one gives a more plausible design reason as for why GRUB does things this way.
          – JoL
          21 hours ago












          Great answer. To your point about special exceptions - a "simpler" exception could have been having two directories e.g. /etc/grub.d/exec for exectuable files/scripts, and /etc/grub.d/static for plain text files, or some other indicator to distinguish these. However, this was the design decision that they went with.
          – Stobor
          14 hours ago




          Great answer. To your point about special exceptions - a "simpler" exception could have been having two directories e.g. /etc/grub.d/exec for exectuable files/scripts, and /etc/grub.d/static for plain text files, or some other indicator to distinguish these. However, this was the design decision that they went with.
          – Stobor
          14 hours ago











          3














          TL;DR: it's a trick to simplify adding new entries to the file



          The whole point is described in one of the Ubuntu's Wiki pages on grub:





          1. Only executable files generate output to grub.cfg during execution of update-grub.




          Output of scripts in /etc/grub.d/ becomes the contents of grub.cfg file.



          Now, what does exec do ? It can either re-wire output for entire script or if a command is provided - the mentioned command overtakes and replaces the script process. What was once shell script with PID 1234 now is tail command with PID 1234.



          Now you already know that tail -n +3 $0 prints everything after the 3rd line in the script itself. So why do we need to do this ? If grub only cares about the output we could just as well do



          cat <<EOF
          menuentry {
          ...
          }
          EOF


          In fact, you will find cat <<EOF example in Fedora documentation, albeit for a different purpose. The whole point is in the comments - ease of use for the users:



          # This file provides an easy way to add custom menu entries.  Simply type the
          # menu entries you want to add after this comment.


          With exec trick, you don't have to know what does cat <<EOF do (spoiler, that's called here-doc), nor you have to remember to add the EOF on the last line. Just add menuentry to the file and be done with it. Plus, if you're scripting adding a menuentry, you can simply append via >> in shell to this file.



          See also:




          • What logic does the command “exec tail -n +3 $0” from grub2 config have?






          share|improve this answer























          • But why not have grub read the files directly? Do you have any idea why they chose to make them executable instead? It would be much simpler to have them as simple text files which are read by whatever process generates the menu, but instead they chose to make them executable and added this (neat) but complex workaround. Is it because grub has its own scripting language as I posit in my answer?
            – terdon
            yesterday










          • @terdon I don't think this has to do anything with the grub language itself. You wouldn't need #!/bin/sh in that case. I suspect this is simply historical reason (carried over from PUPA codebase ) and a design decision inspired by SysV type of scripting.
            – Sergiy Kolodyazhnyy
            yesterday










          • @terdon This actually inspired a question: unix.stackexchange.com/q/492966/85039
            – Sergiy Kolodyazhnyy
            yesterday
















          3














          TL;DR: it's a trick to simplify adding new entries to the file



          The whole point is described in one of the Ubuntu's Wiki pages on grub:





          1. Only executable files generate output to grub.cfg during execution of update-grub.




          Output of scripts in /etc/grub.d/ becomes the contents of grub.cfg file.



          Now, what does exec do ? It can either re-wire output for entire script or if a command is provided - the mentioned command overtakes and replaces the script process. What was once shell script with PID 1234 now is tail command with PID 1234.



          Now you already know that tail -n +3 $0 prints everything after the 3rd line in the script itself. So why do we need to do this ? If grub only cares about the output we could just as well do



          cat <<EOF
          menuentry {
          ...
          }
          EOF


          In fact, you will find cat <<EOF example in Fedora documentation, albeit for a different purpose. The whole point is in the comments - ease of use for the users:



          # This file provides an easy way to add custom menu entries.  Simply type the
          # menu entries you want to add after this comment.


          With exec trick, you don't have to know what does cat <<EOF do (spoiler, that's called here-doc), nor you have to remember to add the EOF on the last line. Just add menuentry to the file and be done with it. Plus, if you're scripting adding a menuentry, you can simply append via >> in shell to this file.



          See also:




          • What logic does the command “exec tail -n +3 $0” from grub2 config have?






          share|improve this answer























          • But why not have grub read the files directly? Do you have any idea why they chose to make them executable instead? It would be much simpler to have them as simple text files which are read by whatever process generates the menu, but instead they chose to make them executable and added this (neat) but complex workaround. Is it because grub has its own scripting language as I posit in my answer?
            – terdon
            yesterday










          • @terdon I don't think this has to do anything with the grub language itself. You wouldn't need #!/bin/sh in that case. I suspect this is simply historical reason (carried over from PUPA codebase ) and a design decision inspired by SysV type of scripting.
            – Sergiy Kolodyazhnyy
            yesterday










          • @terdon This actually inspired a question: unix.stackexchange.com/q/492966/85039
            – Sergiy Kolodyazhnyy
            yesterday














          3












          3








          3






          TL;DR: it's a trick to simplify adding new entries to the file



          The whole point is described in one of the Ubuntu's Wiki pages on grub:





          1. Only executable files generate output to grub.cfg during execution of update-grub.




          Output of scripts in /etc/grub.d/ becomes the contents of grub.cfg file.



          Now, what does exec do ? It can either re-wire output for entire script or if a command is provided - the mentioned command overtakes and replaces the script process. What was once shell script with PID 1234 now is tail command with PID 1234.



          Now you already know that tail -n +3 $0 prints everything after the 3rd line in the script itself. So why do we need to do this ? If grub only cares about the output we could just as well do



          cat <<EOF
          menuentry {
          ...
          }
          EOF


          In fact, you will find cat <<EOF example in Fedora documentation, albeit for a different purpose. The whole point is in the comments - ease of use for the users:



          # This file provides an easy way to add custom menu entries.  Simply type the
          # menu entries you want to add after this comment.


          With exec trick, you don't have to know what does cat <<EOF do (spoiler, that's called here-doc), nor you have to remember to add the EOF on the last line. Just add menuentry to the file and be done with it. Plus, if you're scripting adding a menuentry, you can simply append via >> in shell to this file.



          See also:




          • What logic does the command “exec tail -n +3 $0” from grub2 config have?






          share|improve this answer














          TL;DR: it's a trick to simplify adding new entries to the file



          The whole point is described in one of the Ubuntu's Wiki pages on grub:





          1. Only executable files generate output to grub.cfg during execution of update-grub.




          Output of scripts in /etc/grub.d/ becomes the contents of grub.cfg file.



          Now, what does exec do ? It can either re-wire output for entire script or if a command is provided - the mentioned command overtakes and replaces the script process. What was once shell script with PID 1234 now is tail command with PID 1234.



          Now you already know that tail -n +3 $0 prints everything after the 3rd line in the script itself. So why do we need to do this ? If grub only cares about the output we could just as well do



          cat <<EOF
          menuentry {
          ...
          }
          EOF


          In fact, you will find cat <<EOF example in Fedora documentation, albeit for a different purpose. The whole point is in the comments - ease of use for the users:



          # This file provides an easy way to add custom menu entries.  Simply type the
          # menu entries you want to add after this comment.


          With exec trick, you don't have to know what does cat <<EOF do (spoiler, that's called here-doc), nor you have to remember to add the EOF on the last line. Just add menuentry to the file and be done with it. Plus, if you're scripting adding a menuentry, you can simply append via >> in shell to this file.



          See also:




          • What logic does the command “exec tail -n +3 $0” from grub2 config have?







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited yesterday

























          answered yesterday









          Sergiy KolodyazhnyySergiy Kolodyazhnyy

          70.1k9144307




          70.1k9144307












          • But why not have grub read the files directly? Do you have any idea why they chose to make them executable instead? It would be much simpler to have them as simple text files which are read by whatever process generates the menu, but instead they chose to make them executable and added this (neat) but complex workaround. Is it because grub has its own scripting language as I posit in my answer?
            – terdon
            yesterday










          • @terdon I don't think this has to do anything with the grub language itself. You wouldn't need #!/bin/sh in that case. I suspect this is simply historical reason (carried over from PUPA codebase ) and a design decision inspired by SysV type of scripting.
            – Sergiy Kolodyazhnyy
            yesterday










          • @terdon This actually inspired a question: unix.stackexchange.com/q/492966/85039
            – Sergiy Kolodyazhnyy
            yesterday


















          • But why not have grub read the files directly? Do you have any idea why they chose to make them executable instead? It would be much simpler to have them as simple text files which are read by whatever process generates the menu, but instead they chose to make them executable and added this (neat) but complex workaround. Is it because grub has its own scripting language as I posit in my answer?
            – terdon
            yesterday










          • @terdon I don't think this has to do anything with the grub language itself. You wouldn't need #!/bin/sh in that case. I suspect this is simply historical reason (carried over from PUPA codebase ) and a design decision inspired by SysV type of scripting.
            – Sergiy Kolodyazhnyy
            yesterday










          • @terdon This actually inspired a question: unix.stackexchange.com/q/492966/85039
            – Sergiy Kolodyazhnyy
            yesterday
















          But why not have grub read the files directly? Do you have any idea why they chose to make them executable instead? It would be much simpler to have them as simple text files which are read by whatever process generates the menu, but instead they chose to make them executable and added this (neat) but complex workaround. Is it because grub has its own scripting language as I posit in my answer?
          – terdon
          yesterday




          But why not have grub read the files directly? Do you have any idea why they chose to make them executable instead? It would be much simpler to have them as simple text files which are read by whatever process generates the menu, but instead they chose to make them executable and added this (neat) but complex workaround. Is it because grub has its own scripting language as I posit in my answer?
          – terdon
          yesterday












          @terdon I don't think this has to do anything with the grub language itself. You wouldn't need #!/bin/sh in that case. I suspect this is simply historical reason (carried over from PUPA codebase ) and a design decision inspired by SysV type of scripting.
          – Sergiy Kolodyazhnyy
          yesterday




          @terdon I don't think this has to do anything with the grub language itself. You wouldn't need #!/bin/sh in that case. I suspect this is simply historical reason (carried over from PUPA codebase ) and a design decision inspired by SysV type of scripting.
          – Sergiy Kolodyazhnyy
          yesterday












          @terdon This actually inspired a question: unix.stackexchange.com/q/492966/85039
          – Sergiy Kolodyazhnyy
          yesterday




          @terdon This actually inspired a question: unix.stackexchange.com/q/492966/85039
          – Sergiy Kolodyazhnyy
          yesterday


















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Ask Ubuntu!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.





          Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


          Please pay close attention to the following guidance:


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2faskubuntu.com%2fquestions%2f1107668%2fmeaning-of-exec-tail-n-3-0-line-in-40-custom-file%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Hivernacle

          Hulsita

          Emilio Artal Fos