有没有办法来源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.sh
或bash 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
$