17

我正在使用 sh 将一些 Windows 批处理文件转换为 Unix 脚本。我有问题,因为某些行为取决于批处理文件中可用的 %~dp0 宏。

有没有 sh 相当于这个?有什么方法可以获取执行脚本所在的目录吗?

4

9 回答 9

11

问题(对您而言)$0是它被设置为用于调用脚本的任何命令行,而不是脚本本身的位置。这会使获取包含脚本的目录的完整路径变得困难,而脚本是您从%~dp0Windows 批处理文件中获得的。

例如,考虑以下脚本dollar.sh

#!/bin/bash
echo $0

如果你运行它,你会得到以下输出:

# ./dollar.sh
./dollar.sh
# /tmp/dollar.sh
/tmp/dollar.sh

因此,要获取脚本的完全限定目录名称,我执行以下操作:

cd `dirname $0`
SCRIPTDIR=`pwd`
cd -

这工作如下:

  1. cd使用命令行中的相对或绝对路径到脚本的目录。
  2. 获取此目录的绝对路径并将其存储在SCRIPTDIR.
  3. 使用“”返回上一个工作目录cd -
于 2008-10-16T10:13:28.710 回答
4

是的你可以!它在争论中。:)

看着

${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 的方法,除非那是不可能的。

于 2008-10-16T09:48:02.413 回答
3

在 linux 下的 bash 中,您可以使用以下命令获取命令的完整路径:

readlink /proc/$$/fd/255

并获取目录:

dir=$(dirname $(readlink /proc/$$/fd/255))

这很丑陋,但我还没有找到另一种方法。

于 2008-10-17T14:37:58.130 回答
2

我试图找到来自另一个脚本的脚本的路径。这就是我的问题,当采购文本只是被复制到调用脚本中时,所以 $0 总是返回有关调用脚本的信息。

我找到了一个解决方法,它只适用于 bash,$BASH_SOURCE 总是有关于它被引用的脚本的信息。即使脚本是来源的,它也会正确解析为原始(来源)脚本。

于 2008-10-16T15:57:53.303 回答
1

尝试这个:

${0%/*}
于 2008-10-16T09:49:06.840 回答
1

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
于 2014-06-19T05:40:12.953 回答
1

这是一个脚本可以在执行或获取时获取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)"
于 2021-12-24T23:07:58.083 回答
1

正确答案是: 如何确定脚本的位置?我想从同一个地方读取一些配置文件。

重要的是要认识到,在一般情况下,这个问题没有解决方案。您可能听说过的任何方法以及将在下面详述的任何方法都有缺陷,并且仅在特定情况下有效。首先,不要依赖脚本的位置,尽量避免这个问题!

在我们深入研究解决方案之前,让我们澄清一些误解。重要的是要了解: 您的脚本实际上没有位置!无论字节最终来自哪里,都没有“一条规范路径”。绝不。$0 不是您问题的答案。如果您认为是这样,您可以停止阅读并编写更多错误,或者您可以接受并继续阅读。...

于 2017-08-28T21:18:07.687 回答
0

我之前试过$0,即:

目录名 $0

它只是返回“。” 即使脚本是由另一个脚本提供的:

. ../somedir/somescript.sh

于 2008-10-16T10:02:03.833 回答