Delete nth line (when counted from the bottom)





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ margin-bottom:0;
}







5















There are unknown number of lines in a file. How to delete nth line (when counted from the bottom) with one-liner command (you may use more than one if it is necessary) on Unix platform.










share|improve this question









New contributor




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



























    5















    There are unknown number of lines in a file. How to delete nth line (when counted from the bottom) with one-liner command (you may use more than one if it is necessary) on Unix platform.










    share|improve this question









    New contributor




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























      5












      5








      5








      There are unknown number of lines in a file. How to delete nth line (when counted from the bottom) with one-liner command (you may use more than one if it is necessary) on Unix platform.










      share|improve this question









      New contributor




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












      There are unknown number of lines in a file. How to delete nth line (when counted from the bottom) with one-liner command (you may use more than one if it is necessary) on Unix platform.







      awk sed perl






      share|improve this question









      New contributor




      Swapnil Dhule 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 question









      New contributor




      Swapnil Dhule 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 question




      share|improve this question








      edited Apr 18 at 9:17







      Swapnil Dhule













      New contributor




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









      asked Apr 17 at 8:53









      Swapnil DhuleSwapnil Dhule

      263




      263




      New contributor




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





      New contributor





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






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






















          8 Answers
          8






          active

          oldest

          votes


















          13














          To remove for example the 4th line from the bottom using sed:



          tac input | sed '4d' | tac


          To overwrite the input file:



          tmpfile=$(mktemp)
          tac input | sed '4d' | tac > "$tmpfile" && mv "$tmpfile" input





          share|improve this answer


























          • Thanks Panki! However this won't delete line from the file. We need permanent change in file.

            – Swapnil Dhule
            Apr 17 at 9:09






          • 2





            Use output redirection to write to a new file, then replace the original one.

            – Panki
            Apr 17 at 9:17



















          3














          Pure sed:





          • If n is 1:



            sed '$ d'


            This is simple: if it's the last line, delete the pattern space, so it's not printed.




          • If n is greater than 1 (and available as $n):



            sed "
            : start
            1,$((n-1)) { N; b start }
            $ { t end; s/^//; D }
            N
            P
            D
            : end
            "


            Note $((n-1)) is expanded by the shell before sed starts.



            This fragment



            : start
            1,$((n-1)) { N; b start }


            stores n-1 lines in the pattern space. If sed reaches the end of the input stream during this loop, the pattern space will be printed automatically (there is no n-th line from the end, no line will be deleted).



            Suppose there is more input. Then, before we get to the last line, this fragment is iterated:



            N   # read the next line of input and append it to the pattern space
            P # print the first line from the pattern space
            D # delete the first line from the pattern space and start a new cycle


            This way the pattern space is our buffer which makes the output several lines "late" according to the input. N from this fragment is able to read the last line of the input as well.



            After the last line is read, this gets executed:



            $ { t end; s/^//; D }


            When this code is executed for the first time, t doesn't branch to end because there was no successful substitution before. Such no-op substitution s/^// is then performed and the first line from the pattern space is deleted (D) without being printed. This is exactly the line you want to be deleted. Since D starts a new cycle, the same line of code will eventually be executed again. This time t will branch to end.



            When sed reaches the end of the script, the pattern space is printed automatically. This way all remaining lines get printed.



            The command will generate the same output for n=2 (valid) and n=1 (invalid). I tried to find a single solution that works regardless of n. I failed, hence the special case when your n is 1.








          share|improve this answer































            2














            This is tagged with sed and awk but the question doesn't mention these as being required for the solution. Here's a Perl filter which removes the 4th-from-last line and prints the result. The output can written to a tmp file and then used to replace the original.



             perl -e '@L = <STDIN>; splice(@L,-4,1); print @L' ./lines.txt





            share|improve this answer

































              2














              if $n hold number of line to delete



              to delete a single line use



              printf "$-%d+1,$-%d+1dnwqn" $n $n| ed -s file


              to delete n last lines



              printf "$-%d,$dnwqn" $n | ed -s file


              where





              • $%d,$d tell ed to delete n last lines (printf will insert n)


              • wq write and quit

              • -s in ed -s will keep ed silent.


              • note that no provision is made to check you have enough line to delete.



              sadly range from end can't be specified in sed ...






              share|improve this answer


























              • What do you mean you can't specify ranges with sed? sed '2,4d' works fine on my end..

                – Panki
                Apr 17 at 9:20











              • I like to add -s to the call to ed; quiets the output a bit.

                – Jeff Schaller
                Apr 17 at 15:45











              • @JeffSchaller done

                – Archemar
                Apr 17 at 18:36



















              1














              Neither standard sed nor awk support editing in place.



              For that, you better use ed(1) or ex(1):



              printf '$-%ddnwn' 1 | ed -s your_file


              Or with here-doc



              ed -s <<'EOT' your_file
              $-1d
              w
              EOT


              With advanced shells like bash, zsh orksh93 you can use the $'...' syntax and here-strings:



              ed -s <<<$'$-1dnw' your_file 


              Notice that the $ address means the last line from the file; so the index 1 there is 0-based; for the 1st line from the end replace the 1 with 0 ($-0), for the 3nd with 2 ($-2), etc.



              Putting it in a function:



              del_nth_line_from_end(){ printf '$-%ddnwn' "$(($2-1))" | ed -s "$1"; }


              Instead of ed -s you can use ex -s or vim -es everywhere.






              share|improve this answer

































                0














                sed cannot calculate nth row from bottom by itself, so we need to that before, e.g. using awk:



                Delete 4th row from bottom:



                delrow=$(awk -v n=4 'END { print NR-n+1 }' file)
                sed -i "${delrow}d" file





                share|improve this answer































                  0














                  An one-line, in-place solution:



                  With gawk, this will delete the 42nd line from the bottom:



                  gawk -i inplace 'i==0 {if(FNR>t){t=FNR}else{i=1}} i==1 && FNR!=t-42 {print}' input input


                  The 42 can be replaced with any number. If 0 is used then the last line is deleted.



                  Notice that the input file is specified twice. This forces two iterations of the file with gawk. In the first iteration (i==0) the total number of lines (t) is established. In the second iteration, the nth line from the end is not output.



                  The file is modified in place by using the -i option.






                  share|improve this answer































                    0














                    You can combine head and tail to achieve this.



                    If the nth line from the bottom needs to be deleted





                    1. head reads from standard input and reports to standard output total -n lines from the top


                    2. tail reads and reports to standard output the bottom n-1 lines from standard input.

                    3. Taken as a whole, the lines are thus reported to standard output in order, with the *nth` line from the end being skipped


                    This solution depends on head leaving the file offset of the open file description just after the last reported line - I believe GNU head does indeed do this when standard input is redirected from a file



                    n=200; tmpfile=$(mktemp) && { head -n -$n; tail -n -$((n-1)); }<file >"$tmpfile" 
                    && mv -- "$tmpfile" file





                    share|improve this answer
























                      Your Answer








                      StackExchange.ready(function() {
                      var channelOptions = {
                      tags: "".split(" "),
                      id: "106"
                      };
                      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: false,
                      noModals: true,
                      showLowRepImageUploadWarning: true,
                      reputationToPostImages: null,
                      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
                      });


                      }
                      });






                      Swapnil Dhule is a new contributor. Be nice, and check out our Code of Conduct.










                      draft saved

                      draft discarded


















                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f512947%2fdelete-nth-line-when-counted-from-the-bottom%23new-answer', 'question_page');
                      }
                      );

                      Post as a guest















                      Required, but never shown

























                      8 Answers
                      8






                      active

                      oldest

                      votes








                      8 Answers
                      8






                      active

                      oldest

                      votes









                      active

                      oldest

                      votes






                      active

                      oldest

                      votes









                      13














                      To remove for example the 4th line from the bottom using sed:



                      tac input | sed '4d' | tac


                      To overwrite the input file:



                      tmpfile=$(mktemp)
                      tac input | sed '4d' | tac > "$tmpfile" && mv "$tmpfile" input





                      share|improve this answer


























                      • Thanks Panki! However this won't delete line from the file. We need permanent change in file.

                        – Swapnil Dhule
                        Apr 17 at 9:09






                      • 2





                        Use output redirection to write to a new file, then replace the original one.

                        – Panki
                        Apr 17 at 9:17
















                      13














                      To remove for example the 4th line from the bottom using sed:



                      tac input | sed '4d' | tac


                      To overwrite the input file:



                      tmpfile=$(mktemp)
                      tac input | sed '4d' | tac > "$tmpfile" && mv "$tmpfile" input





                      share|improve this answer


























                      • Thanks Panki! However this won't delete line from the file. We need permanent change in file.

                        – Swapnil Dhule
                        Apr 17 at 9:09






                      • 2





                        Use output redirection to write to a new file, then replace the original one.

                        – Panki
                        Apr 17 at 9:17














                      13












                      13








                      13







                      To remove for example the 4th line from the bottom using sed:



                      tac input | sed '4d' | tac


                      To overwrite the input file:



                      tmpfile=$(mktemp)
                      tac input | sed '4d' | tac > "$tmpfile" && mv "$tmpfile" input





                      share|improve this answer















                      To remove for example the 4th line from the bottom using sed:



                      tac input | sed '4d' | tac


                      To overwrite the input file:



                      tmpfile=$(mktemp)
                      tac input | sed '4d' | tac > "$tmpfile" && mv "$tmpfile" input






                      share|improve this answer














                      share|improve this answer



                      share|improve this answer








                      edited Apr 17 at 18:22









                      glenn jackman

                      53.2k573114




                      53.2k573114










                      answered Apr 17 at 8:57









                      PankiPanki

                      1,030514




                      1,030514













                      • Thanks Panki! However this won't delete line from the file. We need permanent change in file.

                        – Swapnil Dhule
                        Apr 17 at 9:09






                      • 2





                        Use output redirection to write to a new file, then replace the original one.

                        – Panki
                        Apr 17 at 9:17



















                      • Thanks Panki! However this won't delete line from the file. We need permanent change in file.

                        – Swapnil Dhule
                        Apr 17 at 9:09






                      • 2





                        Use output redirection to write to a new file, then replace the original one.

                        – Panki
                        Apr 17 at 9:17

















                      Thanks Panki! However this won't delete line from the file. We need permanent change in file.

                      – Swapnil Dhule
                      Apr 17 at 9:09





                      Thanks Panki! However this won't delete line from the file. We need permanent change in file.

                      – Swapnil Dhule
                      Apr 17 at 9:09




                      2




                      2





                      Use output redirection to write to a new file, then replace the original one.

                      – Panki
                      Apr 17 at 9:17





                      Use output redirection to write to a new file, then replace the original one.

                      – Panki
                      Apr 17 at 9:17













                      3














                      Pure sed:





                      • If n is 1:



                        sed '$ d'


                        This is simple: if it's the last line, delete the pattern space, so it's not printed.




                      • If n is greater than 1 (and available as $n):



                        sed "
                        : start
                        1,$((n-1)) { N; b start }
                        $ { t end; s/^//; D }
                        N
                        P
                        D
                        : end
                        "


                        Note $((n-1)) is expanded by the shell before sed starts.



                        This fragment



                        : start
                        1,$((n-1)) { N; b start }


                        stores n-1 lines in the pattern space. If sed reaches the end of the input stream during this loop, the pattern space will be printed automatically (there is no n-th line from the end, no line will be deleted).



                        Suppose there is more input. Then, before we get to the last line, this fragment is iterated:



                        N   # read the next line of input and append it to the pattern space
                        P # print the first line from the pattern space
                        D # delete the first line from the pattern space and start a new cycle


                        This way the pattern space is our buffer which makes the output several lines "late" according to the input. N from this fragment is able to read the last line of the input as well.



                        After the last line is read, this gets executed:



                        $ { t end; s/^//; D }


                        When this code is executed for the first time, t doesn't branch to end because there was no successful substitution before. Such no-op substitution s/^// is then performed and the first line from the pattern space is deleted (D) without being printed. This is exactly the line you want to be deleted. Since D starts a new cycle, the same line of code will eventually be executed again. This time t will branch to end.



                        When sed reaches the end of the script, the pattern space is printed automatically. This way all remaining lines get printed.



                        The command will generate the same output for n=2 (valid) and n=1 (invalid). I tried to find a single solution that works regardless of n. I failed, hence the special case when your n is 1.








                      share|improve this answer




























                        3














                        Pure sed:





                        • If n is 1:



                          sed '$ d'


                          This is simple: if it's the last line, delete the pattern space, so it's not printed.




                        • If n is greater than 1 (and available as $n):



                          sed "
                          : start
                          1,$((n-1)) { N; b start }
                          $ { t end; s/^//; D }
                          N
                          P
                          D
                          : end
                          "


                          Note $((n-1)) is expanded by the shell before sed starts.



                          This fragment



                          : start
                          1,$((n-1)) { N; b start }


                          stores n-1 lines in the pattern space. If sed reaches the end of the input stream during this loop, the pattern space will be printed automatically (there is no n-th line from the end, no line will be deleted).



                          Suppose there is more input. Then, before we get to the last line, this fragment is iterated:



                          N   # read the next line of input and append it to the pattern space
                          P # print the first line from the pattern space
                          D # delete the first line from the pattern space and start a new cycle


                          This way the pattern space is our buffer which makes the output several lines "late" according to the input. N from this fragment is able to read the last line of the input as well.



                          After the last line is read, this gets executed:



                          $ { t end; s/^//; D }


                          When this code is executed for the first time, t doesn't branch to end because there was no successful substitution before. Such no-op substitution s/^// is then performed and the first line from the pattern space is deleted (D) without being printed. This is exactly the line you want to be deleted. Since D starts a new cycle, the same line of code will eventually be executed again. This time t will branch to end.



                          When sed reaches the end of the script, the pattern space is printed automatically. This way all remaining lines get printed.



                          The command will generate the same output for n=2 (valid) and n=1 (invalid). I tried to find a single solution that works regardless of n. I failed, hence the special case when your n is 1.








                        share|improve this answer


























                          3












                          3








                          3







                          Pure sed:





                          • If n is 1:



                            sed '$ d'


                            This is simple: if it's the last line, delete the pattern space, so it's not printed.




                          • If n is greater than 1 (and available as $n):



                            sed "
                            : start
                            1,$((n-1)) { N; b start }
                            $ { t end; s/^//; D }
                            N
                            P
                            D
                            : end
                            "


                            Note $((n-1)) is expanded by the shell before sed starts.



                            This fragment



                            : start
                            1,$((n-1)) { N; b start }


                            stores n-1 lines in the pattern space. If sed reaches the end of the input stream during this loop, the pattern space will be printed automatically (there is no n-th line from the end, no line will be deleted).



                            Suppose there is more input. Then, before we get to the last line, this fragment is iterated:



                            N   # read the next line of input and append it to the pattern space
                            P # print the first line from the pattern space
                            D # delete the first line from the pattern space and start a new cycle


                            This way the pattern space is our buffer which makes the output several lines "late" according to the input. N from this fragment is able to read the last line of the input as well.



                            After the last line is read, this gets executed:



                            $ { t end; s/^//; D }


                            When this code is executed for the first time, t doesn't branch to end because there was no successful substitution before. Such no-op substitution s/^// is then performed and the first line from the pattern space is deleted (D) without being printed. This is exactly the line you want to be deleted. Since D starts a new cycle, the same line of code will eventually be executed again. This time t will branch to end.



                            When sed reaches the end of the script, the pattern space is printed automatically. This way all remaining lines get printed.



                            The command will generate the same output for n=2 (valid) and n=1 (invalid). I tried to find a single solution that works regardless of n. I failed, hence the special case when your n is 1.








                          share|improve this answer













                          Pure sed:





                          • If n is 1:



                            sed '$ d'


                            This is simple: if it's the last line, delete the pattern space, so it's not printed.




                          • If n is greater than 1 (and available as $n):



                            sed "
                            : start
                            1,$((n-1)) { N; b start }
                            $ { t end; s/^//; D }
                            N
                            P
                            D
                            : end
                            "


                            Note $((n-1)) is expanded by the shell before sed starts.



                            This fragment



                            : start
                            1,$((n-1)) { N; b start }


                            stores n-1 lines in the pattern space. If sed reaches the end of the input stream during this loop, the pattern space will be printed automatically (there is no n-th line from the end, no line will be deleted).



                            Suppose there is more input. Then, before we get to the last line, this fragment is iterated:



                            N   # read the next line of input and append it to the pattern space
                            P # print the first line from the pattern space
                            D # delete the first line from the pattern space and start a new cycle


                            This way the pattern space is our buffer which makes the output several lines "late" according to the input. N from this fragment is able to read the last line of the input as well.



                            After the last line is read, this gets executed:



                            $ { t end; s/^//; D }


                            When this code is executed for the first time, t doesn't branch to end because there was no successful substitution before. Such no-op substitution s/^// is then performed and the first line from the pattern space is deleted (D) without being printed. This is exactly the line you want to be deleted. Since D starts a new cycle, the same line of code will eventually be executed again. This time t will branch to end.



                            When sed reaches the end of the script, the pattern space is printed automatically. This way all remaining lines get printed.



                            The command will generate the same output for n=2 (valid) and n=1 (invalid). I tried to find a single solution that works regardless of n. I failed, hence the special case when your n is 1.









                          share|improve this answer












                          share|improve this answer



                          share|improve this answer










                          answered Apr 17 at 12:03









                          Kamil MaciorowskiKamil Maciorowski

                          1,85211030




                          1,85211030























                              2














                              This is tagged with sed and awk but the question doesn't mention these as being required for the solution. Here's a Perl filter which removes the 4th-from-last line and prints the result. The output can written to a tmp file and then used to replace the original.



                               perl -e '@L = <STDIN>; splice(@L,-4,1); print @L' ./lines.txt





                              share|improve this answer






























                                2














                                This is tagged with sed and awk but the question doesn't mention these as being required for the solution. Here's a Perl filter which removes the 4th-from-last line and prints the result. The output can written to a tmp file and then used to replace the original.



                                 perl -e '@L = <STDIN>; splice(@L,-4,1); print @L' ./lines.txt





                                share|improve this answer




























                                  2












                                  2








                                  2







                                  This is tagged with sed and awk but the question doesn't mention these as being required for the solution. Here's a Perl filter which removes the 4th-from-last line and prints the result. The output can written to a tmp file and then used to replace the original.



                                   perl -e '@L = <STDIN>; splice(@L,-4,1); print @L' ./lines.txt





                                  share|improve this answer















                                  This is tagged with sed and awk but the question doesn't mention these as being required for the solution. Here's a Perl filter which removes the 4th-from-last line and prints the result. The output can written to a tmp file and then used to replace the original.



                                   perl -e '@L = <STDIN>; splice(@L,-4,1); print @L' ./lines.txt






                                  share|improve this answer














                                  share|improve this answer



                                  share|improve this answer








                                  edited Apr 17 at 18:25









                                  glenn jackman

                                  53.2k573114




                                  53.2k573114










                                  answered Apr 17 at 13:48









                                  Mark StosbergMark Stosberg

                                  4,1131227




                                  4,1131227























                                      2














                                      if $n hold number of line to delete



                                      to delete a single line use



                                      printf "$-%d+1,$-%d+1dnwqn" $n $n| ed -s file


                                      to delete n last lines



                                      printf "$-%d,$dnwqn" $n | ed -s file


                                      where





                                      • $%d,$d tell ed to delete n last lines (printf will insert n)


                                      • wq write and quit

                                      • -s in ed -s will keep ed silent.


                                      • note that no provision is made to check you have enough line to delete.



                                      sadly range from end can't be specified in sed ...






                                      share|improve this answer


























                                      • What do you mean you can't specify ranges with sed? sed '2,4d' works fine on my end..

                                        – Panki
                                        Apr 17 at 9:20











                                      • I like to add -s to the call to ed; quiets the output a bit.

                                        – Jeff Schaller
                                        Apr 17 at 15:45











                                      • @JeffSchaller done

                                        – Archemar
                                        Apr 17 at 18:36
















                                      2














                                      if $n hold number of line to delete



                                      to delete a single line use



                                      printf "$-%d+1,$-%d+1dnwqn" $n $n| ed -s file


                                      to delete n last lines



                                      printf "$-%d,$dnwqn" $n | ed -s file


                                      where





                                      • $%d,$d tell ed to delete n last lines (printf will insert n)


                                      • wq write and quit

                                      • -s in ed -s will keep ed silent.


                                      • note that no provision is made to check you have enough line to delete.



                                      sadly range from end can't be specified in sed ...






                                      share|improve this answer


























                                      • What do you mean you can't specify ranges with sed? sed '2,4d' works fine on my end..

                                        – Panki
                                        Apr 17 at 9:20











                                      • I like to add -s to the call to ed; quiets the output a bit.

                                        – Jeff Schaller
                                        Apr 17 at 15:45











                                      • @JeffSchaller done

                                        – Archemar
                                        Apr 17 at 18:36














                                      2












                                      2








                                      2







                                      if $n hold number of line to delete



                                      to delete a single line use



                                      printf "$-%d+1,$-%d+1dnwqn" $n $n| ed -s file


                                      to delete n last lines



                                      printf "$-%d,$dnwqn" $n | ed -s file


                                      where





                                      • $%d,$d tell ed to delete n last lines (printf will insert n)


                                      • wq write and quit

                                      • -s in ed -s will keep ed silent.


                                      • note that no provision is made to check you have enough line to delete.



                                      sadly range from end can't be specified in sed ...






                                      share|improve this answer















                                      if $n hold number of line to delete



                                      to delete a single line use



                                      printf "$-%d+1,$-%d+1dnwqn" $n $n| ed -s file


                                      to delete n last lines



                                      printf "$-%d,$dnwqn" $n | ed -s file


                                      where





                                      • $%d,$d tell ed to delete n last lines (printf will insert n)


                                      • wq write and quit

                                      • -s in ed -s will keep ed silent.


                                      • note that no provision is made to check you have enough line to delete.



                                      sadly range from end can't be specified in sed ...







                                      share|improve this answer














                                      share|improve this answer



                                      share|improve this answer








                                      edited Apr 17 at 18:36

























                                      answered Apr 17 at 9:12









                                      ArchemarArchemar

                                      20.7k93973




                                      20.7k93973













                                      • What do you mean you can't specify ranges with sed? sed '2,4d' works fine on my end..

                                        – Panki
                                        Apr 17 at 9:20











                                      • I like to add -s to the call to ed; quiets the output a bit.

                                        – Jeff Schaller
                                        Apr 17 at 15:45











                                      • @JeffSchaller done

                                        – Archemar
                                        Apr 17 at 18:36



















                                      • What do you mean you can't specify ranges with sed? sed '2,4d' works fine on my end..

                                        – Panki
                                        Apr 17 at 9:20











                                      • I like to add -s to the call to ed; quiets the output a bit.

                                        – Jeff Schaller
                                        Apr 17 at 15:45











                                      • @JeffSchaller done

                                        – Archemar
                                        Apr 17 at 18:36

















                                      What do you mean you can't specify ranges with sed? sed '2,4d' works fine on my end..

                                      – Panki
                                      Apr 17 at 9:20





                                      What do you mean you can't specify ranges with sed? sed '2,4d' works fine on my end..

                                      – Panki
                                      Apr 17 at 9:20













                                      I like to add -s to the call to ed; quiets the output a bit.

                                      – Jeff Schaller
                                      Apr 17 at 15:45





                                      I like to add -s to the call to ed; quiets the output a bit.

                                      – Jeff Schaller
                                      Apr 17 at 15:45













                                      @JeffSchaller done

                                      – Archemar
                                      Apr 17 at 18:36





                                      @JeffSchaller done

                                      – Archemar
                                      Apr 17 at 18:36











                                      1














                                      Neither standard sed nor awk support editing in place.



                                      For that, you better use ed(1) or ex(1):



                                      printf '$-%ddnwn' 1 | ed -s your_file


                                      Or with here-doc



                                      ed -s <<'EOT' your_file
                                      $-1d
                                      w
                                      EOT


                                      With advanced shells like bash, zsh orksh93 you can use the $'...' syntax and here-strings:



                                      ed -s <<<$'$-1dnw' your_file 


                                      Notice that the $ address means the last line from the file; so the index 1 there is 0-based; for the 1st line from the end replace the 1 with 0 ($-0), for the 3nd with 2 ($-2), etc.



                                      Putting it in a function:



                                      del_nth_line_from_end(){ printf '$-%ddnwn' "$(($2-1))" | ed -s "$1"; }


                                      Instead of ed -s you can use ex -s or vim -es everywhere.






                                      share|improve this answer






























                                        1














                                        Neither standard sed nor awk support editing in place.



                                        For that, you better use ed(1) or ex(1):



                                        printf '$-%ddnwn' 1 | ed -s your_file


                                        Or with here-doc



                                        ed -s <<'EOT' your_file
                                        $-1d
                                        w
                                        EOT


                                        With advanced shells like bash, zsh orksh93 you can use the $'...' syntax and here-strings:



                                        ed -s <<<$'$-1dnw' your_file 


                                        Notice that the $ address means the last line from the file; so the index 1 there is 0-based; for the 1st line from the end replace the 1 with 0 ($-0), for the 3nd with 2 ($-2), etc.



                                        Putting it in a function:



                                        del_nth_line_from_end(){ printf '$-%ddnwn' "$(($2-1))" | ed -s "$1"; }


                                        Instead of ed -s you can use ex -s or vim -es everywhere.






                                        share|improve this answer




























                                          1












                                          1








                                          1







                                          Neither standard sed nor awk support editing in place.



                                          For that, you better use ed(1) or ex(1):



                                          printf '$-%ddnwn' 1 | ed -s your_file


                                          Or with here-doc



                                          ed -s <<'EOT' your_file
                                          $-1d
                                          w
                                          EOT


                                          With advanced shells like bash, zsh orksh93 you can use the $'...' syntax and here-strings:



                                          ed -s <<<$'$-1dnw' your_file 


                                          Notice that the $ address means the last line from the file; so the index 1 there is 0-based; for the 1st line from the end replace the 1 with 0 ($-0), for the 3nd with 2 ($-2), etc.



                                          Putting it in a function:



                                          del_nth_line_from_end(){ printf '$-%ddnwn' "$(($2-1))" | ed -s "$1"; }


                                          Instead of ed -s you can use ex -s or vim -es everywhere.






                                          share|improve this answer















                                          Neither standard sed nor awk support editing in place.



                                          For that, you better use ed(1) or ex(1):



                                          printf '$-%ddnwn' 1 | ed -s your_file


                                          Or with here-doc



                                          ed -s <<'EOT' your_file
                                          $-1d
                                          w
                                          EOT


                                          With advanced shells like bash, zsh orksh93 you can use the $'...' syntax and here-strings:



                                          ed -s <<<$'$-1dnw' your_file 


                                          Notice that the $ address means the last line from the file; so the index 1 there is 0-based; for the 1st line from the end replace the 1 with 0 ($-0), for the 3nd with 2 ($-2), etc.



                                          Putting it in a function:



                                          del_nth_line_from_end(){ printf '$-%ddnwn' "$(($2-1))" | ed -s "$1"; }


                                          Instead of ed -s you can use ex -s or vim -es everywhere.







                                          share|improve this answer














                                          share|improve this answer



                                          share|improve this answer








                                          edited Apr 17 at 15:55

























                                          answered Apr 17 at 15:24









                                          mosvymosvy

                                          10.5k11338




                                          10.5k11338























                                              0














                                              sed cannot calculate nth row from bottom by itself, so we need to that before, e.g. using awk:



                                              Delete 4th row from bottom:



                                              delrow=$(awk -v n=4 'END { print NR-n+1 }' file)
                                              sed -i "${delrow}d" file





                                              share|improve this answer




























                                                0














                                                sed cannot calculate nth row from bottom by itself, so we need to that before, e.g. using awk:



                                                Delete 4th row from bottom:



                                                delrow=$(awk -v n=4 'END { print NR-n+1 }' file)
                                                sed -i "${delrow}d" file





                                                share|improve this answer


























                                                  0












                                                  0








                                                  0







                                                  sed cannot calculate nth row from bottom by itself, so we need to that before, e.g. using awk:



                                                  Delete 4th row from bottom:



                                                  delrow=$(awk -v n=4 'END { print NR-n+1 }' file)
                                                  sed -i "${delrow}d" file





                                                  share|improve this answer













                                                  sed cannot calculate nth row from bottom by itself, so we need to that before, e.g. using awk:



                                                  Delete 4th row from bottom:



                                                  delrow=$(awk -v n=4 'END { print NR-n+1 }' file)
                                                  sed -i "${delrow}d" file






                                                  share|improve this answer












                                                  share|improve this answer



                                                  share|improve this answer










                                                  answered Apr 17 at 9:25









                                                  RoVoRoVo

                                                  3,980317




                                                  3,980317























                                                      0














                                                      An one-line, in-place solution:



                                                      With gawk, this will delete the 42nd line from the bottom:



                                                      gawk -i inplace 'i==0 {if(FNR>t){t=FNR}else{i=1}} i==1 && FNR!=t-42 {print}' input input


                                                      The 42 can be replaced with any number. If 0 is used then the last line is deleted.



                                                      Notice that the input file is specified twice. This forces two iterations of the file with gawk. In the first iteration (i==0) the total number of lines (t) is established. In the second iteration, the nth line from the end is not output.



                                                      The file is modified in place by using the -i option.






                                                      share|improve this answer




























                                                        0














                                                        An one-line, in-place solution:



                                                        With gawk, this will delete the 42nd line from the bottom:



                                                        gawk -i inplace 'i==0 {if(FNR>t){t=FNR}else{i=1}} i==1 && FNR!=t-42 {print}' input input


                                                        The 42 can be replaced with any number. If 0 is used then the last line is deleted.



                                                        Notice that the input file is specified twice. This forces two iterations of the file with gawk. In the first iteration (i==0) the total number of lines (t) is established. In the second iteration, the nth line from the end is not output.



                                                        The file is modified in place by using the -i option.






                                                        share|improve this answer


























                                                          0












                                                          0








                                                          0







                                                          An one-line, in-place solution:



                                                          With gawk, this will delete the 42nd line from the bottom:



                                                          gawk -i inplace 'i==0 {if(FNR>t){t=FNR}else{i=1}} i==1 && FNR!=t-42 {print}' input input


                                                          The 42 can be replaced with any number. If 0 is used then the last line is deleted.



                                                          Notice that the input file is specified twice. This forces two iterations of the file with gawk. In the first iteration (i==0) the total number of lines (t) is established. In the second iteration, the nth line from the end is not output.



                                                          The file is modified in place by using the -i option.






                                                          share|improve this answer













                                                          An one-line, in-place solution:



                                                          With gawk, this will delete the 42nd line from the bottom:



                                                          gawk -i inplace 'i==0 {if(FNR>t){t=FNR}else{i=1}} i==1 && FNR!=t-42 {print}' input input


                                                          The 42 can be replaced with any number. If 0 is used then the last line is deleted.



                                                          Notice that the input file is specified twice. This forces two iterations of the file with gawk. In the first iteration (i==0) the total number of lines (t) is established. In the second iteration, the nth line from the end is not output.



                                                          The file is modified in place by using the -i option.







                                                          share|improve this answer












                                                          share|improve this answer



                                                          share|improve this answer










                                                          answered Apr 17 at 13:02









                                                          ltn100ltn100

                                                          22326




                                                          22326























                                                              0














                                                              You can combine head and tail to achieve this.



                                                              If the nth line from the bottom needs to be deleted





                                                              1. head reads from standard input and reports to standard output total -n lines from the top


                                                              2. tail reads and reports to standard output the bottom n-1 lines from standard input.

                                                              3. Taken as a whole, the lines are thus reported to standard output in order, with the *nth` line from the end being skipped


                                                              This solution depends on head leaving the file offset of the open file description just after the last reported line - I believe GNU head does indeed do this when standard input is redirected from a file



                                                              n=200; tmpfile=$(mktemp) && { head -n -$n; tail -n -$((n-1)); }<file >"$tmpfile" 
                                                              && mv -- "$tmpfile" file





                                                              share|improve this answer




























                                                                0














                                                                You can combine head and tail to achieve this.



                                                                If the nth line from the bottom needs to be deleted





                                                                1. head reads from standard input and reports to standard output total -n lines from the top


                                                                2. tail reads and reports to standard output the bottom n-1 lines from standard input.

                                                                3. Taken as a whole, the lines are thus reported to standard output in order, with the *nth` line from the end being skipped


                                                                This solution depends on head leaving the file offset of the open file description just after the last reported line - I believe GNU head does indeed do this when standard input is redirected from a file



                                                                n=200; tmpfile=$(mktemp) && { head -n -$n; tail -n -$((n-1)); }<file >"$tmpfile" 
                                                                && mv -- "$tmpfile" file





                                                                share|improve this answer


























                                                                  0












                                                                  0








                                                                  0







                                                                  You can combine head and tail to achieve this.



                                                                  If the nth line from the bottom needs to be deleted





                                                                  1. head reads from standard input and reports to standard output total -n lines from the top


                                                                  2. tail reads and reports to standard output the bottom n-1 lines from standard input.

                                                                  3. Taken as a whole, the lines are thus reported to standard output in order, with the *nth` line from the end being skipped


                                                                  This solution depends on head leaving the file offset of the open file description just after the last reported line - I believe GNU head does indeed do this when standard input is redirected from a file



                                                                  n=200; tmpfile=$(mktemp) && { head -n -$n; tail -n -$((n-1)); }<file >"$tmpfile" 
                                                                  && mv -- "$tmpfile" file





                                                                  share|improve this answer













                                                                  You can combine head and tail to achieve this.



                                                                  If the nth line from the bottom needs to be deleted





                                                                  1. head reads from standard input and reports to standard output total -n lines from the top


                                                                  2. tail reads and reports to standard output the bottom n-1 lines from standard input.

                                                                  3. Taken as a whole, the lines are thus reported to standard output in order, with the *nth` line from the end being skipped


                                                                  This solution depends on head leaving the file offset of the open file description just after the last reported line - I believe GNU head does indeed do this when standard input is redirected from a file



                                                                  n=200; tmpfile=$(mktemp) && { head -n -$n; tail -n -$((n-1)); }<file >"$tmpfile" 
                                                                  && mv -- "$tmpfile" file






                                                                  share|improve this answer












                                                                  share|improve this answer



                                                                  share|improve this answer










                                                                  answered Apr 17 at 14:25









                                                                  iruvariruvar

                                                                  12.5k63063




                                                                  12.5k63063






















                                                                      Swapnil Dhule is a new contributor. Be nice, and check out our Code of Conduct.










                                                                      draft saved

                                                                      draft discarded


















                                                                      Swapnil Dhule is a new contributor. Be nice, and check out our Code of Conduct.













                                                                      Swapnil Dhule is a new contributor. Be nice, and check out our Code of Conduct.












                                                                      Swapnil Dhule is a new contributor. Be nice, and check out our Code of Conduct.
















                                                                      Thanks for contributing an answer to Unix & Linux Stack Exchange!


                                                                      • 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%2funix.stackexchange.com%2fquestions%2f512947%2fdelete-nth-line-when-counted-from-the-bottom%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

                                                                      Plaza Victoria

                                                                      Puebla de Zaragoza

                                                                      Musa