我正在使用 sh 将一些 Windows 批处理文件转换为 Unix 脚本。我有问题,因为某些行为取决于批处理文件中可用的 %~dp0 宏。
有没有 sh 相当于这个?有什么方法可以获取执行脚本所在的目录吗?
我正在使用 sh 将一些 Windows 批处理文件转换为 Unix 脚本。我有问题,因为某些行为取决于批处理文件中可用的 %~dp0 宏。
有没有 sh 相当于这个?有什么方法可以获取执行脚本所在的目录吗?
问题(对您而言)$0
是它被设置为用于调用脚本的任何命令行,而不是脚本本身的位置。这会使获取包含脚本的目录的完整路径变得困难,而脚本是您从%~dp0
Windows 批处理文件中获得的。
例如,考虑以下脚本dollar.sh
:
#!/bin/bash
echo $0
如果你运行它,你会得到以下输出:
# ./dollar.sh
./dollar.sh
# /tmp/dollar.sh
/tmp/dollar.sh
因此,要获取脚本的完全限定目录名称,我执行以下操作:
cd `dirname $0`
SCRIPTDIR=`pwd`
cd -
这工作如下:
cd
使用命令行中的相对或绝对路径到脚本的目录。SCRIPTDIR
.cd -
。是的你可以!它在争论中。:)
看着
${0}
将其与
{$var%Pattern}
Remove from $var the shortest part of $Pattern that matches the back end of $var.
你想要的只是
${0%/*}
我推荐Advanced Bash Scripting Guide (这也是上述信息的来源)。特别是关于将 DOS 批处理文件转换为 Shell 脚本的部分 可能对您有用。:)
如果我误解了你,你可能需要将它与“pwd”的输出结合起来。因为它只包含调用脚本的路径!尝试以下脚本:
#!/bin/bash
called_path=${0%/*}
stripped=${called_path#[^/]*}
real_path=`pwd`$stripped
echo "called path: $called_path"
echo "stripped: $stripped"
echo "pwd: `pwd`"
echo "real path: $real_path
不过,这需要一些工作。我推荐使用 Dave Webb 的方法,除非那是不可能的。
在 linux 下的 bash 中,您可以使用以下命令获取命令的完整路径:
readlink /proc/$$/fd/255
并获取目录:
dir=$(dirname $(readlink /proc/$$/fd/255))
这很丑陋,但我还没有找到另一种方法。
我试图找到来自另一个脚本的脚本的路径。这就是我的问题,当采购文本只是被复制到调用脚本中时,所以 $0 总是返回有关调用脚本的信息。
我找到了一个解决方法,它只适用于 bash,$BASH_SOURCE 总是有关于它被引用的脚本的信息。即使脚本是来源的,它也会正确解析为原始(来源)脚本。
尝试这个:
${0%/*}
This should work for bash shell:
dir=$(dirname $(readlink -m $BASH_SOURCE))
Test script:
#!/bin/bash
echo $(dirname $(readlink -m $BASH_SOURCE))
Run test:
$ ./somedir/test.sh
/tmp/somedir
$ source ./somedir/test.sh
/tmp/somedir
$ bash ./somedir/test.sh
/tmp/somedir
$ . ./somedir/test.sh
/tmp/somedir
这是一个脚本可以在执行或获取时获取shell文件的真实路径。
在bash、zsh、dash、sh中测试。
顺便说一句:你应该自己清理冗长的代码。
#!/usr/bin/env bash
_ORIGINAL_PWD_=$(pwd)
if test -n "$BASH" ; then _SH_FILE_RUN_PATH_=${BASH_SOURCE[0]}
elif test -n "$TMOUT"; then _SH_FILE_RUN_PATH_=${.sh.file}
elif test -n "$ZSH_NAME" ; then _SH_FILE_RUN_PATH_=${(%):-%x}
# Use lsof,tr,tail,sed to retrieve path
else _SH_FILE_RUN_PATH_=$(lsof -p $$ -Fn0 | tr -d '\0' | tail -1 | sed 's/^[^\/]*//g')
fi
echo "\$0: $0"
echo "\$_: $_"
echo "\$BASH: $BASH"
echo "\$TMOUT: $TMOUT"
echo "\$ZSH_NAME: $ZSH_NAME"
echo "\${0##*/}: ${0##*/}"
echo "EXECUTING FILE PATH: $_SH_FILE_RUN_PATH_"
cd "$(dirname "$_SH_FILE_RUN_PATH_")" || return
_SH_FILE_RUN_BASENAME_=$(basename "$_SH_FILE_RUN_PATH_")
# Iterate down a (possible) chain of symlinks as lsof of macOS doesn't have -f option.
while [ -L "$_SH_FILE_RUN_BASENAME_" ]
do
_SH_FILE_REAL_PATH_=$(readlink "$_SH_FILE_RUN_BASENAME_")
cd "$(dirname "$_SH_FILE_REAL_PATH_")" || return
_SH_FILE_RUN_BASENAME_=$(basename "$_SH_FILE_REAL_PATH_")
done
# Compute the canonicalized name by finding the physical path
# for the directory we're in and appending the target file.
_SH_FILE_REAL_DIR_=$(pwd -P)
_SH_FILE_REAL_PATH_=$_SH_FILE_REAL_DIR_/$_SH_FILE_RUN_BASENAME_
echo "EXECUTING REAL PATH: $_SH_FILE_REAL_PATH_"
echo "EXECUTING FILE DIR: $_SH_FILE_REAL_DIR_"
cd "$_ORIGINAL_PWD_" || return
echo "CURRENT PWD: $(pwd)"
正确答案是: 如何确定脚本的位置?我想从同一个地方读取一些配置文件。
重要的是要认识到,在一般情况下,这个问题没有解决方案。您可能听说过的任何方法以及将在下面详述的任何方法都有缺陷,并且仅在特定情况下有效。首先,不要依赖脚本的位置,尽量避免这个问题!
在我们深入研究解决方案之前,让我们澄清一些误解。重要的是要了解: 您的脚本实际上没有位置!无论字节最终来自哪里,都没有“一条规范路径”。绝不。$0 不是您问题的答案。如果您认为是这样,您可以停止阅读并编写更多错误,或者您可以接受并继续阅读。...
我之前试过$0,即:
目录名 $0
它只是返回“。” 即使脚本是由另一个脚本提供的:
. ../somedir/somescript.sh