How do I find the line number in Bash when an error occured?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
16
down vote

favorite
8












How do you find the line number in Bash where an error occurred?



Example



I create the following simple script with line numbers to explain what we need. The script will copy files from



cp $file1 $file2
cp $file3 $file4


When one of the cp commands fail then the function will exit with exit 1. We want to add the ability to the function to also print the error with the line number (for example, 8 or 12).



Is this possible?



Sample script



1 #!/bin/bash
2
3
4 function in_case_fail
5 [[ $1 -ne 0 ]] && echo "fail on $2" && exit 1
6
7
8 cp $file1 $file2
9 in_case_fail $? "cp $file1 $file2"
10
11
12 cp $file3 $file4
13 in_case_fail $? "cp $file3 $file4"
14






share|improve this question






















  • Related - stackoverflow.com/questions/24398691/…
    – slm♦
    Aug 12 at 18:26










  • You could use set -x and/or set -v to trace what has been executed. Not exactly what you asked for but it will probably be helpful, too.
    – Rolf
    Aug 23 at 8:34














up vote
16
down vote

favorite
8












How do you find the line number in Bash where an error occurred?



Example



I create the following simple script with line numbers to explain what we need. The script will copy files from



cp $file1 $file2
cp $file3 $file4


When one of the cp commands fail then the function will exit with exit 1. We want to add the ability to the function to also print the error with the line number (for example, 8 or 12).



Is this possible?



Sample script



1 #!/bin/bash
2
3
4 function in_case_fail
5 [[ $1 -ne 0 ]] && echo "fail on $2" && exit 1
6
7
8 cp $file1 $file2
9 in_case_fail $? "cp $file1 $file2"
10
11
12 cp $file3 $file4
13 in_case_fail $? "cp $file3 $file4"
14






share|improve this question






















  • Related - stackoverflow.com/questions/24398691/…
    – slm♦
    Aug 12 at 18:26










  • You could use set -x and/or set -v to trace what has been executed. Not exactly what you asked for but it will probably be helpful, too.
    – Rolf
    Aug 23 at 8:34












up vote
16
down vote

favorite
8









up vote
16
down vote

favorite
8






8





How do you find the line number in Bash where an error occurred?



Example



I create the following simple script with line numbers to explain what we need. The script will copy files from



cp $file1 $file2
cp $file3 $file4


When one of the cp commands fail then the function will exit with exit 1. We want to add the ability to the function to also print the error with the line number (for example, 8 or 12).



Is this possible?



Sample script



1 #!/bin/bash
2
3
4 function in_case_fail
5 [[ $1 -ne 0 ]] && echo "fail on $2" && exit 1
6
7
8 cp $file1 $file2
9 in_case_fail $? "cp $file1 $file2"
10
11
12 cp $file3 $file4
13 in_case_fail $? "cp $file3 $file4"
14






share|improve this question














How do you find the line number in Bash where an error occurred?



Example



I create the following simple script with line numbers to explain what we need. The script will copy files from



cp $file1 $file2
cp $file3 $file4


When one of the cp commands fail then the function will exit with exit 1. We want to add the ability to the function to also print the error with the line number (for example, 8 or 12).



Is this possible?



Sample script



1 #!/bin/bash
2
3
4 function in_case_fail
5 [[ $1 -ne 0 ]] && echo "fail on $2" && exit 1
6
7
8 cp $file1 $file2
9 in_case_fail $? "cp $file1 $file2"
10
11
12 cp $file3 $file4
13 in_case_fail $? "cp $file3 $file4"
14








share|improve this question













share|improve this question




share|improve this question








edited Aug 13 at 1:46









Peter Mortensen

79148




79148










asked Aug 12 at 17:18









yael

2,0301145




2,0301145











  • Related - stackoverflow.com/questions/24398691/…
    – slm♦
    Aug 12 at 18:26










  • You could use set -x and/or set -v to trace what has been executed. Not exactly what you asked for but it will probably be helpful, too.
    – Rolf
    Aug 23 at 8:34
















  • Related - stackoverflow.com/questions/24398691/…
    – slm♦
    Aug 12 at 18:26










  • You could use set -x and/or set -v to trace what has been executed. Not exactly what you asked for but it will probably be helpful, too.
    – Rolf
    Aug 23 at 8:34















Related - stackoverflow.com/questions/24398691/…
– slm♦
Aug 12 at 18:26




Related - stackoverflow.com/questions/24398691/…
– slm♦
Aug 12 at 18:26












You could use set -x and/or set -v to trace what has been executed. Not exactly what you asked for but it will probably be helpful, too.
– Rolf
Aug 23 at 8:34




You could use set -x and/or set -v to trace what has been executed. Not exactly what you asked for but it will probably be helpful, too.
– Rolf
Aug 23 at 8:34










3 Answers
3






active

oldest

votes

















up vote
25
down vote



accepted










Rather than use your function, I'd use this method instead:



$ cat yael.bash
#!/bin/bash

set -eE -o functrace

file1=f1
file2=f2
file3=f3
file4=f4

failure()
local lineno=$1
local msg=$2
echo "Failed at $lineno: $msg"

trap 'failure $LINENO "$BASH_COMMAND"' ERR

cp -- "$file1" "$file2"
cp -- "$file3" "$file4"


This works by trapping on ERR and then calling the failure() function with the current line number + bash command that was executed.



Example



Here I've not taken any care to create the files, f1, f2, f3, or f4. When I run the above script:



$ ./yael.bash
cp: cannot stat ‘f1’: No such file or directory
Failed at 17: cp -- "$file1" "$file2"


It fails, reporting the line number plus command that was executed.






share|improve this answer





























    up vote
    12
    down vote













    In addition to LINENO containing the current line number, there are the BASH_LINENO and FUNCNAME (and BASH_SOURCE) arrays that contain the function names and line numbers they're called from.



    So you could do something like this:



    #!/bin/bash

    error()
    printf "'%s' failed with exit code %d in function '%s' at line %d.n" "$1-something" "$?" "$FUNCNAME[1]" "$BASH_LINENO[0]"


    foo() error "this thing"
    ( exit 123 )

    foo


    Running that would print



    'that thing' failed with exit code 123 in function 'foo' at line 9.


    If you use set -e, or trap ... ERR to automatically detect errors, note that they have some caveats. It's also harder to include a description of what the script was doing at the time (as you did in your example), though that might be more useful to a regular user than just the line number.



    See e.g. these for the issues with set -e and others:



    • Why does set -e not work inside subshells with parenthesis () followed by an OR list ||?

    • bash -e exits when let or expr evaluates to 0

    • BashFAQ 105: Why doesn't set -e (or set -o errexit, or trap ERR) do what I expected?





    share|improve this answer





























      up vote
      10
      down vote













      Bash has a built-in variable $LINENO which is replaced by the current line number when in a statement, so you can do



      in_case_fail $? "at $LINENO: cp $file1 $file2"


      You could also try using trap ... ERR which runs when a command fails (if the result is not tested). Eg:



      trap 'rc=$?; echo "error code $rc at $LINENO"; exit $rc' ERR


      Then if a command like cp $file1 $file2 fails you will get the error message with the line number and an exit. You will also find the command in error in variable $BASH_COMMAND (though not any redirections etc.).






      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',
        convertImagesToLinks: false,
        noModals: false,
        showLowRepImageUploadWarning: true,
        reputationToPostImages: null,
        bindNavPrevention: true,
        postfix: "",
        onDemand: true,
        discardSelector: ".discard-answer"
        ,immediatelyShowMarkdownHelp:true
        );



        );













         

        draft saved


        draft discarded


















        StackExchange.ready(
        function ()
        StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f462156%2fhow-do-i-find-the-line-number-in-bash-when-an-error-occured%23new-answer', 'question_page');

        );

        Post as a guest






























        3 Answers
        3






        active

        oldest

        votes








        3 Answers
        3






        active

        oldest

        votes









        active

        oldest

        votes






        active

        oldest

        votes








        up vote
        25
        down vote



        accepted










        Rather than use your function, I'd use this method instead:



        $ cat yael.bash
        #!/bin/bash

        set -eE -o functrace

        file1=f1
        file2=f2
        file3=f3
        file4=f4

        failure()
        local lineno=$1
        local msg=$2
        echo "Failed at $lineno: $msg"

        trap 'failure $LINENO "$BASH_COMMAND"' ERR

        cp -- "$file1" "$file2"
        cp -- "$file3" "$file4"


        This works by trapping on ERR and then calling the failure() function with the current line number + bash command that was executed.



        Example



        Here I've not taken any care to create the files, f1, f2, f3, or f4. When I run the above script:



        $ ./yael.bash
        cp: cannot stat ‘f1’: No such file or directory
        Failed at 17: cp -- "$file1" "$file2"


        It fails, reporting the line number plus command that was executed.






        share|improve this answer


























          up vote
          25
          down vote



          accepted










          Rather than use your function, I'd use this method instead:



          $ cat yael.bash
          #!/bin/bash

          set -eE -o functrace

          file1=f1
          file2=f2
          file3=f3
          file4=f4

          failure()
          local lineno=$1
          local msg=$2
          echo "Failed at $lineno: $msg"

          trap 'failure $LINENO "$BASH_COMMAND"' ERR

          cp -- "$file1" "$file2"
          cp -- "$file3" "$file4"


          This works by trapping on ERR and then calling the failure() function with the current line number + bash command that was executed.



          Example



          Here I've not taken any care to create the files, f1, f2, f3, or f4. When I run the above script:



          $ ./yael.bash
          cp: cannot stat ‘f1’: No such file or directory
          Failed at 17: cp -- "$file1" "$file2"


          It fails, reporting the line number plus command that was executed.






          share|improve this answer
























            up vote
            25
            down vote



            accepted







            up vote
            25
            down vote



            accepted






            Rather than use your function, I'd use this method instead:



            $ cat yael.bash
            #!/bin/bash

            set -eE -o functrace

            file1=f1
            file2=f2
            file3=f3
            file4=f4

            failure()
            local lineno=$1
            local msg=$2
            echo "Failed at $lineno: $msg"

            trap 'failure $LINENO "$BASH_COMMAND"' ERR

            cp -- "$file1" "$file2"
            cp -- "$file3" "$file4"


            This works by trapping on ERR and then calling the failure() function with the current line number + bash command that was executed.



            Example



            Here I've not taken any care to create the files, f1, f2, f3, or f4. When I run the above script:



            $ ./yael.bash
            cp: cannot stat ‘f1’: No such file or directory
            Failed at 17: cp -- "$file1" "$file2"


            It fails, reporting the line number plus command that was executed.






            share|improve this answer














            Rather than use your function, I'd use this method instead:



            $ cat yael.bash
            #!/bin/bash

            set -eE -o functrace

            file1=f1
            file2=f2
            file3=f3
            file4=f4

            failure()
            local lineno=$1
            local msg=$2
            echo "Failed at $lineno: $msg"

            trap 'failure $LINENO "$BASH_COMMAND"' ERR

            cp -- "$file1" "$file2"
            cp -- "$file3" "$file4"


            This works by trapping on ERR and then calling the failure() function with the current line number + bash command that was executed.



            Example



            Here I've not taken any care to create the files, f1, f2, f3, or f4. When I run the above script:



            $ ./yael.bash
            cp: cannot stat ‘f1’: No such file or directory
            Failed at 17: cp -- "$file1" "$file2"


            It fails, reporting the line number plus command that was executed.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Aug 19 at 11:50









            ilkkachu

            50.2k677138




            50.2k677138










            answered Aug 12 at 17:23









            slm♦

            237k65484657




            237k65484657






















                up vote
                12
                down vote













                In addition to LINENO containing the current line number, there are the BASH_LINENO and FUNCNAME (and BASH_SOURCE) arrays that contain the function names and line numbers they're called from.



                So you could do something like this:



                #!/bin/bash

                error()
                printf "'%s' failed with exit code %d in function '%s' at line %d.n" "$1-something" "$?" "$FUNCNAME[1]" "$BASH_LINENO[0]"


                foo() error "this thing"
                ( exit 123 )

                foo


                Running that would print



                'that thing' failed with exit code 123 in function 'foo' at line 9.


                If you use set -e, or trap ... ERR to automatically detect errors, note that they have some caveats. It's also harder to include a description of what the script was doing at the time (as you did in your example), though that might be more useful to a regular user than just the line number.



                See e.g. these for the issues with set -e and others:



                • Why does set -e not work inside subshells with parenthesis () followed by an OR list ||?

                • bash -e exits when let or expr evaluates to 0

                • BashFAQ 105: Why doesn't set -e (or set -o errexit, or trap ERR) do what I expected?





                share|improve this answer


























                  up vote
                  12
                  down vote













                  In addition to LINENO containing the current line number, there are the BASH_LINENO and FUNCNAME (and BASH_SOURCE) arrays that contain the function names and line numbers they're called from.



                  So you could do something like this:



                  #!/bin/bash

                  error()
                  printf "'%s' failed with exit code %d in function '%s' at line %d.n" "$1-something" "$?" "$FUNCNAME[1]" "$BASH_LINENO[0]"


                  foo() error "this thing"
                  ( exit 123 )

                  foo


                  Running that would print



                  'that thing' failed with exit code 123 in function 'foo' at line 9.


                  If you use set -e, or trap ... ERR to automatically detect errors, note that they have some caveats. It's also harder to include a description of what the script was doing at the time (as you did in your example), though that might be more useful to a regular user than just the line number.



                  See e.g. these for the issues with set -e and others:



                  • Why does set -e not work inside subshells with parenthesis () followed by an OR list ||?

                  • bash -e exits when let or expr evaluates to 0

                  • BashFAQ 105: Why doesn't set -e (or set -o errexit, or trap ERR) do what I expected?





                  share|improve this answer
























                    up vote
                    12
                    down vote










                    up vote
                    12
                    down vote









                    In addition to LINENO containing the current line number, there are the BASH_LINENO and FUNCNAME (and BASH_SOURCE) arrays that contain the function names and line numbers they're called from.



                    So you could do something like this:



                    #!/bin/bash

                    error()
                    printf "'%s' failed with exit code %d in function '%s' at line %d.n" "$1-something" "$?" "$FUNCNAME[1]" "$BASH_LINENO[0]"


                    foo() error "this thing"
                    ( exit 123 )

                    foo


                    Running that would print



                    'that thing' failed with exit code 123 in function 'foo' at line 9.


                    If you use set -e, or trap ... ERR to automatically detect errors, note that they have some caveats. It's also harder to include a description of what the script was doing at the time (as you did in your example), though that might be more useful to a regular user than just the line number.



                    See e.g. these for the issues with set -e and others:



                    • Why does set -e not work inside subshells with parenthesis () followed by an OR list ||?

                    • bash -e exits when let or expr evaluates to 0

                    • BashFAQ 105: Why doesn't set -e (or set -o errexit, or trap ERR) do what I expected?





                    share|improve this answer














                    In addition to LINENO containing the current line number, there are the BASH_LINENO and FUNCNAME (and BASH_SOURCE) arrays that contain the function names and line numbers they're called from.



                    So you could do something like this:



                    #!/bin/bash

                    error()
                    printf "'%s' failed with exit code %d in function '%s' at line %d.n" "$1-something" "$?" "$FUNCNAME[1]" "$BASH_LINENO[0]"


                    foo() error "this thing"
                    ( exit 123 )

                    foo


                    Running that would print



                    'that thing' failed with exit code 123 in function 'foo' at line 9.


                    If you use set -e, or trap ... ERR to automatically detect errors, note that they have some caveats. It's also harder to include a description of what the script was doing at the time (as you did in your example), though that might be more useful to a regular user than just the line number.



                    See e.g. these for the issues with set -e and others:



                    • Why does set -e not work inside subshells with parenthesis () followed by an OR list ||?

                    • bash -e exits when let or expr evaluates to 0

                    • BashFAQ 105: Why doesn't set -e (or set -o errexit, or trap ERR) do what I expected?






                    share|improve this answer














                    share|improve this answer



                    share|improve this answer








                    edited Aug 12 at 19:12

























                    answered Aug 12 at 19:00









                    ilkkachu

                    50.2k677138




                    50.2k677138




















                        up vote
                        10
                        down vote













                        Bash has a built-in variable $LINENO which is replaced by the current line number when in a statement, so you can do



                        in_case_fail $? "at $LINENO: cp $file1 $file2"


                        You could also try using trap ... ERR which runs when a command fails (if the result is not tested). Eg:



                        trap 'rc=$?; echo "error code $rc at $LINENO"; exit $rc' ERR


                        Then if a command like cp $file1 $file2 fails you will get the error message with the line number and an exit. You will also find the command in error in variable $BASH_COMMAND (though not any redirections etc.).






                        share|improve this answer


























                          up vote
                          10
                          down vote













                          Bash has a built-in variable $LINENO which is replaced by the current line number when in a statement, so you can do



                          in_case_fail $? "at $LINENO: cp $file1 $file2"


                          You could also try using trap ... ERR which runs when a command fails (if the result is not tested). Eg:



                          trap 'rc=$?; echo "error code $rc at $LINENO"; exit $rc' ERR


                          Then if a command like cp $file1 $file2 fails you will get the error message with the line number and an exit. You will also find the command in error in variable $BASH_COMMAND (though not any redirections etc.).






                          share|improve this answer
























                            up vote
                            10
                            down vote










                            up vote
                            10
                            down vote









                            Bash has a built-in variable $LINENO which is replaced by the current line number when in a statement, so you can do



                            in_case_fail $? "at $LINENO: cp $file1 $file2"


                            You could also try using trap ... ERR which runs when a command fails (if the result is not tested). Eg:



                            trap 'rc=$?; echo "error code $rc at $LINENO"; exit $rc' ERR


                            Then if a command like cp $file1 $file2 fails you will get the error message with the line number and an exit. You will also find the command in error in variable $BASH_COMMAND (though not any redirections etc.).






                            share|improve this answer














                            Bash has a built-in variable $LINENO which is replaced by the current line number when in a statement, so you can do



                            in_case_fail $? "at $LINENO: cp $file1 $file2"


                            You could also try using trap ... ERR which runs when a command fails (if the result is not tested). Eg:



                            trap 'rc=$?; echo "error code $rc at $LINENO"; exit $rc' ERR


                            Then if a command like cp $file1 $file2 fails you will get the error message with the line number and an exit. You will also find the command in error in variable $BASH_COMMAND (though not any redirections etc.).







                            share|improve this answer














                            share|improve this answer



                            share|improve this answer








                            edited Aug 12 at 18:34

























                            answered Aug 12 at 18:22









                            meuh

                            29.5k11750




                            29.5k11750



























                                 

                                draft saved


                                draft discarded















































                                 


                                draft saved


                                draft discarded














                                StackExchange.ready(
                                function ()
                                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f462156%2fhow-do-i-find-the-line-number-in-bash-when-an-error-occured%23new-answer', 'question_page');

                                );

                                Post as a guest













































































                                Comments

                                Popular posts from this blog

                                What does second last employer means? [closed]

                                List of Gilmore Girls characters

                                Confectionery