45

Is there any variable in bash that contains the name of the .sh file executed? The line number would be great too.

I want to use it in error messages such as:

echo "ERROR: [$FILE:L$LINE] $somefile not found"
codeforester
  • 28,846
  • 11
  • 78
  • 104
user368507
  • 1,238
  • 1
  • 13
  • 25
  • See the logging and error handling implementation here: https://github.com/codeforester/base/blob/master/lib/stdlib.sh which involves the use of Bash builtin `caller` command as well as `BASH_SOURCE` and `BASH_LINENO` arrays to log the context of execution / dump stack trace. – codeforester Apr 09 '19 at 05:47

4 Answers4

43
#!/bin/bash

echo $LINENO
echo `basename $0`

$LINENO for the current line number $0 for the current file. I used basename to ensure you only get the file name and not the path.

UPDATE:

#!/bin/bash

MY_NAME=`basename $0`

function ouch {
   echo "Fail @ [${MY_NAME}:${1}]"
   exit 1
}

ouch $LINENO

You have to pass the line as a parameter if you use the function approach else you will get the line of the function definition.

ezpz
  • 10,955
  • 6
  • 35
  • 36
26

I find the "BASH_SOURCE" and "BASH_LINENO" built-in arrays very useful:

$ cat xx
#!/bin/bash

_ERR_HDR_FMT="%.23s %s[%s]: "
_ERR_MSG_FMT="${_ERR_HDR_FMT}%s\n"

error_msg() {
  printf "$_ERR_MSG_FMT" $(date +%F.%T.%N) ${BASH_SOURCE[1]##*/} ${BASH_LINENO[0]} "${@}"
}

error_msg "here"


error_msg "and here"

Invoking xx yields

2010-06-16.15:33:13.069 xx[11]: here
2010-06-16.15:33:13.073 xx[14]: and here
iconoclast
  • 17,897
  • 10
  • 91
  • 122
Kevin Little
  • 11,232
  • 5
  • 35
  • 46
8

You just need to

echo $LINENO
echo $(basename $0)
Loxley
  • 1,771
  • 17
  • 20
5

Here's how to do it in a reusable function. if the following is in a file named script:

#!/bin/bash
debug() {
  echo "${BASH_SOURCE[1]##*/}:${FUNCNAME[1]}[${BASH_LINENO[0]}]" > /dev/tty
}
debug

This produces the output:

script:main[5]    

Which indicates the line on which debug was called.


The following will print out the filename, function, line and an optional message.

Also works in zsh for extra goodness.

# Say the file, line number and optional message for debugging
# Inspired by bash's `caller` builtin
# Thanks to https://unix.stackexchange.com/a/453153/143394
function yelp () {
  # shellcheck disable=SC2154  # undeclared zsh variables in bash
  if [[ $BASH_VERSION ]]; then
    local file=${BASH_SOURCE[1]##*/} func=${FUNCNAME[1]} line=${BASH_LINENO[0]}
  else  # zsh
    emulate -L zsh  # because we may be sourced by zsh `emulate bash -c`
    # $funcfiletrace has format:  file:line
    local file=${funcfiletrace[1]%:*} line=${funcfiletrace[1]##*:}
    local func=${funcstack[2]}
    [[ $func =~ / ]] && func=source  # $func may be filename. Use bash behaviour
  fi
  echo "${file##*/}:$func:$line $*" > /dev/tty
}
Tom Hale
  • 25,410
  • 16
  • 132
  • 172
  • This is a really nice solution. Though I think there must be a way to make it more compact, I haven't found it I like to use `set -euo pipefail` in a lot of my production/critical shell scripts so I slightly modified it to use `if [[ ${BASH_VERSION:-} ]]; then` in place of `if [[ $BASH_VERSION ]]; then` Otherwise I get `yelp:3: BASH_VERSION: parameter not set` which is expected, because of the strictness of `set -u`, which will bail any time a variable is accessed that isn't set – adam Jan 02 '21 at 17:59