如何从脚本内确定源 tcsh 或 bash shell 脚本的路径

如何从脚本内确定源 tcsh 或 bash shell 脚本的路径

有没有办法来源shell脚本找到自身的路径?我主要关心的是bash,尽管我有一些同事使用tcsh.

我猜我在这里可能没有太多运气,因为采购导致命令在当前 shell 中执行,因此$0仍然是当前 shell 的调用,而不是源脚本。我最好的想法是让source $script $script第一个位置参数包含必要的信息。有人有更好的办法吗?

明确地说,我是采购脚本,而不是运行它:

source foo.bash

答案1

在 中tcsh$_如果文件是来源的,则脚本的开头将包含该位置;$0如果文件已运行,则脚本的开头将包含该位置。

#!/bin/tcsh
set sourced=($_)
if ("$sourced" != "") then
    echo "sourced $sourced[2]"
endif
if ("$0" != "tcsh") then
    echo "run $0"
endif

在重击中:

#!/bin/bash
[[ $0 != $BASH_SOURCE ]] && echo "Script is being sourced" || echo "Script is being run"

答案2

我认为你可以使用$BASH_SOURCE变量。它返回执行的路径:

示例脚本:

打印脚本路径.sh:

#!/usr/bin/env bash

echo "$BASH_SOURCE"

使其可执行:

chmod +x print_script_path.sh

对于此脚本的不同位置,示例运行及其输出:

pbm@tauri ~ $ /home/pbm/print_script_path.sh 
/home/pbm/print_script_path.sh
pbm@tauri ~ $ ./print_script_path.sh
./print_script_path.sh
pbm@tauri ~ $ source /home/pbm/print_script_path.sh 
/home/pbm/print_script_path.sh
pbm@tauri ~ $ source ./print_script_path.sh
./print_script_path.sh

因此,下一步我们应该检查路径是否是相对的。如果不是相对的,一切都好。如果是,我们可以用 来检查路径pwd,用/和连接$BASH_SOURCE

答案3

此解决方案仅适用于 bash,不适用于 tcsh。请注意,如果您尝试从函数内查找路径,则通常提供的答案${BASH_SOURCE[0]}将不起作用。

我发现这条线始终有效,无论文件是作为源文件还是作为脚本运行。

echo "${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}"

如果您想readlink以递归或非递归方式跟踪符号链接,请在上面获得的路径上使用。

双引号可防止路径中的空格将结果分割为数组,并且不仅对于 是必需的echo,而且在任何使用它的上下文中都是必需的。由于echo在数组项之间插入单个空格,因此除非路径中存在两个或多个连续空格,否则差异将被隐藏。

这是一个用于尝试并将其与其他建议的解决方案进行比较的脚本。将其调用为source test1/test2/test_script.shbash test1/test2/test_script.sh

#
# Location: test1/test2/test_script.sh
#
echo $0
echo $_
echo "${BASH_SOURCE}"
echo "${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}"

cur_file="${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}"
cur_dir="$(dirname "${cur_file}")"
source "${cur_dir}/func_def.sh"

function test_within_func_inside {
    echo "${BASH_SOURCE}"
    echo "${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}"
}

echo "Testing within function inside"
test_within_func_inside

echo "Testing within function outside"
test_within_func_outside
#
# Location: test1/test2/func_def.sh
#
function test_within_func_outside {
    echo "${BASH_SOURCE}"
    echo "${BASH_SOURCE[${#BASH_SOURCE[@]} - 1]}"
}

单行代码起作用的原因可以通过BASH_SOURCE环境变量及其关联变量的使用来解释FUNCNAME

BASH_SOURCE

一个数组变量,其成员是源文件名,其中定义了 FUNCNAME 数组变量中相应的 shell 函数名称。 shell 函数 ${FUNCNAME[$i]} 在文件 ${BASH_SOURCE[$i]} 中定义,并从 ${BASH_SOURCE[$i+1]} 调用。

函数名

一个数组变量,包含当前执行调用堆栈中的所有 shell 函数的名称。索引为 0 的元素是任何当前正在执行的 shell 函数的名称。最底部的元素(索引最高的元素)是“main”。该变量仅在 shell 函数执行时存在。对 FUNCNAME 的赋值无效并返回错误状态。如果 FUNCNAME 未设置,它将失去其特殊属性,即使随后重置也是如此。

该变量可以与 BASH_LINENO 和 BASH_SOURCE 一起使用。 FUNCNAME 的每个元素在 BASH_LINENO 和 BASH_SOURCE 中都有相应的元素来描述调用堆栈。例如,${FUNCNAME[$i]} 是从文件 ${BASH_SOURCE[$i+1]} 的行号 ${BASH_LINENO[$i]} 处调用的。内置调用者使用此信息显示当前调用堆栈。

[来源:Bash 手册]

答案4

为了彻底性和搜索者的利益,这就是它们的作用...它是一个社区 wiki,所以请随意添加其他 shell 的等效项(显然,$BASH_SOURCE 会有所不同)。

测试.sh:

#! /bin/sh
called=$_
echo $called
echo $_
echo $0
echo $BASH_SOURCE

测试2.sh:

#! /bin/sh
source ./test.sh

重击:

$./test2.sh
./test2.sh
./test2.sh
./test2.sh
./test.sh
$ sh ./test2.sh
/bin/sh
/bin/sh
./test2.sh
./test.sh

短跑

$./test2.sh
./test2.sh
./test2.sh
./test2.sh

$/bin/sh ./test2.sh
/bin/sh
/bin/sh
./test2.sh

$

兹什

$ ./test2.sh
./test.sh
./test.sh
./test.sh

$ zsh test.sh

echo
test.sh

$

相关内容