Bash函数 - 返回父脚本文件路径

时间:2013-08-07 22:55:09

标签: bash

我有一个包含一个函数的bash脚本,该函数由许多不同的bash脚本提供。此函数可能会因其输入而失败,我想在函数中创建日志记录以确定导致失败的脚本。

如, source /path/to/function.sh

我最接近的是:

ps --no-heading -ocmd -p $$

如果使用完整文件路径运行父脚本,则返回:

/bin/bash /path/to/parent.sh

但如果从相对路径运行父脚本,则无法提供完整路径,返回:

/bin/bash ./parent.sh

理想情况下,我想要一种可靠地返回两种情况的父脚本文件路径的方法。

我想我可以让每个父脚本将其文件路径传递给该函数(通过$ 0或类似),但这似乎难以强制执行并且不是非常优雅。

任何想法或替代方法?我不应该担心相对路径的情况,只是使用完整/绝对文件路径的一切?

谢谢!

我正在使用Centos 5.9。 Bash版 - GNU bash,版本3.2.25(1)-release(x86_64-redhat-linux-gnu)

3 个答案:

答案 0 :(得分:1)

父脚本一开始导出

 "`pwd`/$0"

左右,进入一个env变量,比如ORIG_SCRIPT,然后在函数中使用ORIG_SCRIPT。

你需要在脚本启动时立即执行此操作,因为$ 0可能与PWD相关,如果稍后在需要ORIG_SCRIPT的值之前更改PWD,则会出现不必要的复杂。

<强>更新

由于您通过$$知道pid,您可能会从/ proc /&lt; PID&gt; / cmdline获得一些内容,但我不知道这个内容究竟是如何工作的。

答案 1 :(得分:1)

您可以使用readlink来跟踪所有符号链接以获得绝对路径。

echo $(readlink -f $0)

答案 2 :(得分:0)

您可以使用${BASH_SOURCE[1]}来获取调用该函数的脚本,但这并不总是在绝对路径表单上。您可以通过readlink -mrealpath或其他shell-script based solutions获取它的绝对路径,但如果您的脚本不时更改目录,则不再将相对路径转换为绝对路径准确,因为这些工具基于当前目录,以获得实际的表格。

然而,有一种解决方法,但这要求您在调用(获取)包含该函数的脚本之前不会更改脚本中的目录。您必须将当前目录保存在该脚本本身中,然后在该目录中构建绝对路径。在包含脚本后,您可以自由更改目录。举个例子:

ORIGINAL_PWD=$PWD

function x {
    local CALLING_SCRIPT="${BASH_SOURCE[1]}"

    if [[ -n $CALLING_SCRIPT ]]; then
        if [[ $CALLING_SCRIPT == /* ]]; then
            CALLING_SCRIPT=$(readlink -m "$CALLING_SCRIPT")
        else
            CALLING_SCRIPT=$(readlink -m "$ORIGINAL_PWD/$CALLING_SCRIPT")
        fi

        echo "Calling script: $CALLING_SCRIPT"
    else
        echo "Caller is not a script."
    fi
}

或者

ORIGINAL_PWD=$PWD

function getabspath {
    local -a T1 T2
    local -i I=0
    local IFS=/ A

    case "$1" in
    /*)
        read -r -a T1 <<< "$1"
        ;;
    *)
        read -r -a T1 <<< "/$PWD/$1"
        ;;
    esac

    T2=()

    for A in "${T1[@]}"; do
        case "$A" in
        ..)
            [[ I -ne 0 ]] && unset T2\[--I\]
            continue
            ;;
        .|'')
            continue
            ;;
        esac

        T2[I++]=$A
    done

    case "$1" in
    */)
        [[ I -ne 0 ]] && __="/${T2[*]}/" || __=/
        ;;
    *)
        [[ I -ne 0 ]] && __="/${T2[*]}" || __=/.
        ;;
    esac
}

function x {
    local CALLING_SCRIPT="${BASH_SOURCE[1]}"

    if [[ -n $CALLING_SCRIPT ]]; then
        if [[ $CALLING_SCRIPT == /* ]]; then
            getabspath "$CALLING_SCRIPT"
        else
            getabspath "$ORIGINAL_PWD/$CALLING_SCRIPT"
        fi

        echo "Calling script: $__"
    else
        echo "Caller is not a script."
    fi
}

您还可以使用FUNCNAME和BASH_LINENO来更具体地处理错误。我不确定他们是否已经在Bash 3.2中得到支持。

如果你实际上有Bash 4.0+,你可以使用关联数组来映射绝对路径,但是如果有两个具有相同名称的脚本或者使用几乎相似的名称调用,则可以覆盖一个值。由于我们无法从BASH_SOURCE中选择我们的密钥,因此无法解决这个问题。

添加注意:您还可以防止脚本多次被不必要地获取,因为它只需要通过Shell Script Loader之类的解决方案。你也可以通过它找到便利。