Equivalent of __FILE__ and __LINE__ in Bash

BashError HandlingEnvironment Variables

Bash Problem Overview


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"

Bash Solutions


Solution 1 - Bash

#!/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.

Solution 2 - Bash

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

Solution 3 - Bash

You just need to

echo $LINENO
echo $(basename $0)

Solution 4 - Bash

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
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser368507View Question on Stackoverflow
Solution 1 - BashezpzView Answer on Stackoverflow
Solution 2 - BashKevin LittleView Answer on Stackoverflow
Solution 3 - BashLoxleyView Answer on Stackoverflow
Solution 4 - BashTom HaleView Answer on Stackoverflow