1

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

例如,源 /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)

4

3 回答 3

1

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

echo $(readlink -f $0)
于 2013-08-07T23:35:36.733 回答
1

一旦父脚本开始导出

 "`pwd`/$0"

或者,进入一个环境变量,比如 ORIG_SCRIPT,然后在函数中使用 ORIG_SCRIPT。

您需要在脚本启动后立即执行此操作,因为 $0 可能与 PWD 相关,并且如果您稍后在需要 ORIG_SCRIPT 的值之前更改 PWD,它会变得不必要地复杂。

更新:

由于您通过 $$ 知道 pid,因此您可能会从 /proc/<PID>/cmdline 得到一些东西,但我不知道这个现在是如何工作的。

于 2013-08-07T23:32:19.853 回答
0

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

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

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之类的解决方案进行一次。您也可以通过它找到便利。

于 2013-08-08T06:07:08.120 回答