从内部获取Bash脚本的源目录

时间:2020-03-05 18:52:31  来源:igfitidea点击:

如何在脚本内获取Bash脚本所在目录的路径?

例如,假设我要使用Bash脚本作为另一个应用程序的启动器。我想将工作目录更改为Bash脚本所在的目录,以便可以对该目录中的文件进行操作,如下所示:

$ ./application

解决方案

回答

使用dirname" $ 0"

#!/bin/bash
echo "The script you are running has basename `basename "
[matt@server1 ~]$ pwd
/home/matt
[matt@server1 ~]$ ./test2.sh
The script you are running has basename test2.sh, dirname .
The present working directory is /home/matt
[matt@server1 ~]$ cd /tmp
[matt@server1 tmp]$ ~/test2.sh
The script you are running has basename test2.sh, dirname /home/matt
The present working directory is /tmp
"`, dirname `dirname "
#!/bin/bash

scriptdir=`dirname "$BASH_SOURCE"`
"`" echo "The present working directory is `pwd`"

如果我们不是从脚本所在的目录中运行脚本,则仅使用pwd将不起作用。

./script

/usr/bin/script

script

回答

我们可以使用$ BASH_SOURCE

#!/bin/sh
PRG="
#!/bin/bash

reldir=`dirname 
cd `dirname 
SELF=$(readlink /proc/$$/fd/255)
`
` cd $reldir directory=`pwd` echo "Directory is $directory"
" # need this for relative symlinks while [ -h "$PRG" ] ; do PRG=`readlink "$PRG"` done scriptdir=`dirname "$PRG"`

请注意,我们需要使用#!/ bin / bash而不是#!/ bin / sh,因为它是bash扩展名

回答

我认为这并不像其他人说的那么容易。 pwd不起作用,因为当前目录不一定是包含脚本的目录。 $ 0也不总是具有该信息。考虑以下三种调用脚本的方法。

pushd . > /dev/null
SCRIPT_PATH="${BASH_SOURCE[0]}"
if ([ -h "${SCRIPT_PATH}" ]); then
  while([ -h "${SCRIPT_PATH}" ]); do cd `dirname "$SCRIPT_PATH"`; 
  SCRIPT_PATH=`readlink "${SCRIPT_PATH}"`; done
fi
cd `dirname ${SCRIPT_PATH}` > /dev/null
SCRIPT_PATH=`pwd`;
popd  > /dev/null

在第一种和第三种方式中,$ 0没有完整的路径信息。在第二个和第三个中,pwd不起作用。以第三种方式获取目录的唯一方法是遍历路径并找到具有正确匹配项的文件。基本上,代码将不得不重做操作系统。

一种执行我们要执行的操作的方法是仅对/ usr / share目录中的数据进行硬编码,然后按完整路径引用。无论如何,数据都不应该在/ usr / bin目录中,所以这可能是要做的事情。

回答

pushd . > /dev/null
SCRIPT_PATH="${BASH_SOURCE[0]}";
if ([ -h "${SCRIPT_PATH}" ]) then
  while([ -h "${SCRIPT_PATH}" ]) do cd `dirname "$SCRIPT_PATH"`; SCRIPT_PATH=`readlink "${SCRIPT_PATH}"`; done
fi
cd `dirname ${SCRIPT_PATH}` > /dev/null
SCRIPT_PATH=`pwd`;
popd  > /dev/null

回答

pwd可以用来找到当前的工作目录,dirname可以用来找到特定文件的目录(运行的命令是$ 0,所以dirname $ 0应该给你当前脚本的目录。 )。

但是,dirname恰好给出了文件名的目录部分,该部分很可能相对于当前工作目录。如果脚本由于某种原因需要更改目录,那么dirname的输出将变得毫无意义。

我建议以下内容:

path="$( dirname "$( which "
source "$( dirname "$( which "
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
" )" )/lib/B"
" )" )"

这样,我们将获得一个绝对目录,而不是相对目录。

由于脚本将在单独的bash实例中运行,因此此后无需还原工作目录,但是如果出于某些原因确实要更改脚本,则可以轻松地将pwd的值分配给更改目录之前的变量,以备将来使用。

虽然只是

SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
  DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null && pwd )"
  SOURCE="$(readlink "$SOURCE")"
  [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
done
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null && pwd )"

解决了问题中的特定场景,我发现绝对路径通常更有用。

回答

这是特定于Linux的,但是我们可以使用:

#!/bin/bash

SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
  TARGET="$(readlink "$SOURCE")"
  if [[ $TARGET == /* ]]; then
    echo "SOURCE '$SOURCE' is an absolute symlink to '$TARGET'"
    SOURCE="$TARGET"
  else
    DIR="$( dirname "$SOURCE" )"
    echo "SOURCE '$SOURCE' is a relative symlink to '$TARGET' (relative to '$DIR')"
    SOURCE="$DIR/$TARGET" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
  fi
done
echo "SOURCE is '$SOURCE'"
RDIR="$( dirname "$SOURCE" )"
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
if [ "$DIR" != "$RDIR" ]; then
  echo "DIR '$RDIR' resolves to '$DIR'"
fi
echo "DIR is '$DIR'"

回答

SOURCE './scriptdir.sh' is a relative symlink to 'sym2/scriptdir.sh' (relative to '.')
SOURCE is './sym2/scriptdir.sh'
DIR './sym2' resolves to '/home/ubuntu/dotfiles/fo fo/real/real1/real2'
DIR is '/home/ubuntu/dotfiles/fo fo/real/real1/real2'

适用于所有版本,包括

  • 通过多个深度软链接调用时,
  • 什么时候归档
  • 当脚本由命令" source"或者"。"(点)运算符调用时。
  • 当从调用方修改了arg $ 0时。
  • " ./script"
  • " / full / path / to / script"
  • " / some / path /../../ another / path / script"
  • " ./some/folder/script"

另外,如果bash脚本本身是一个相对的符号链接,则我们要跟随它并返回链接脚本的完整路径:

`dirname 
$(dirname "
LIBDIR=$(dirname "$(readlink -f "$(type -P 
SELF=`readlink /proc/$$/fd/255`
|| echo
cd $(dirname $(which 
DIR=$(/usr/bin/pwd)
) )
)")") source $LIBDIR/lib.sh
")
`

不管如何调用,都以完整路径给出" SCRIPT_PATH"。
只需确保在脚本开始时找到它即可。

此注释和代码为Copyleft,是GPL2.0或者更高版本或者CC-SA 3.0(CreativeCommons Share Alike)或者更高版本的可选许可证。 (c)2008. 保留所有权利。没有任何形式的保证。你被警告了。
http://www.gnu.org/licenses/gpl-2.0.txt
http://creativecommons.org/licenses/by-sa/3.0/
18eedfe1c99df68dc94d4a94712a71aaa8e1e9e36cacf421b9463dd2bbaa02906d0d6656

回答

这在bash-3.2中有效:

SCRIPT_DIR=$(dirname $(cd "$(dirname "$BASH_SOURCE")"; pwd))

这是其用法的示例:

假设我们有一个〜/ bin目录,位于$ PATH中。我们在此目录中有脚本A。它获取脚本〜/ bin / lib / B。我们知道所包含的脚本相对于原始脚本的位置(子目录lib)的位置,而不是相对于用户当前目录的位置。

这可以通过以下方法解决(在A内):

ME=`type -p 
dirname "
dirname "$(readlink -f "
#!/bin/bash
echo "pwd: `pwd`"
echo "$0: 
>>>$ ./whatdir.sh 
pwd: /Users/phatblat
>>>$ /Users/phatblat/whatdir.sh 
pwd: /Users/phatblat
>>>$ cd /tmp
>>>$ ~/whatdir.sh 
pwd: /tmp
>>>$ ln -s ~/whatdir.sh whatdirlink.sh
>>>$ ./whatdirlink.sh 
pwd: /tmp
function getScriptAbsoluteDir { # fold>>
    # @description used to get the script path
    # @param  the script 
SCRIPT_DIR=''
pushd "$(dirname "$(readlink -f "$BASH_SOURCE")")" > /dev/null && {
    SCRIPT_DIR="$PWD"
    popd > /dev/null
}
parameter local script_invoke_path="" local cwd=`pwd` # absolute path ? if so, the first character is a / if test "x${script_invoke_path:0:1}" = 'x/' then RESULT=`dirname "$script_invoke_path"` else RESULT=`dirname "$cwd/$script_invoke_path"` fi } # <<fold
: ./whatdirlink.sh basename: whatdirlink.sh dirname: . dirname/readlink: /Users/phatblat
: /Users/phatblat/whatdir.sh basename: whatdir.sh dirname: /Users/phatblat dirname/readlink: /Users/phatblat
: /Users/phatblat/whatdir.sh basename: whatdir.sh dirname: /Users/phatblat dirname/readlink: /Users/phatblat
: ./whatdir.sh basename: whatdir.sh dirname: . dirname/readlink: /Users/phatblat
" echo "basename: `basename
#!/bin/bash
echo "pwd: `pwd`"
echo "$0: 
cd "`dirname "
SCRIPT_LOC="`ps -p $$ | sed /PID/d | sed s:.*/Network/:/Network/: |
sed s:.*/Volumes/:/Volumes/:`"
"`"
" echo "basename: `basename "
SCRIPT_DIR=$( cd ${0%/*} && pwd -P )
"`" echo "dirname: `dirname "
script="`readlink -f "${BASH_SOURCE[0]}"`"
dir="`dirname "$script"`"
"`"
`" echo "dirname: `dirname
DIR=$(cd "$(dirname "##代码##")"; pwd)
`" echo "dirname/readlink: $(dirname $(readlink -f ##代码##))"
")"
"
` MDIR="${ME%/*}" WORK_DIR=$(cd $MDIR && pwd)

无论用户身在何处或者如何调用脚本,都将始终有效。

回答

##代码##

是有用的单行代码,无论从何处调用脚本,它都将为我们提供脚本的完整目录名称。

只要用于查找脚本的路径的最后一个组成部分不是符号链接(目录链接都可以),它将起作用。如果我们还想解析到脚本本身的任何链接,则需要一个多行解决方案:

##代码##

最后一个将与别名,sourcebash -c,symlinks等的任意组合一起使用。

请注意:如果在运行此代码片段之前将cd移至其他目录,则结果可能不正确!另外,请注意$ CDPATH陷阱。

要了解它是如何工作的,请尝试运行以下更详细的形式:

##代码##

它会打印类似:

##代码##

回答

简短答案:

##代码##

或者(最好):

##代码##

回答

我通常这样做:

##代码##

回答

嗯,如果在路径中的基本名和目录名只是不切
并很难走这条路(如果父母没有出口PATH的话!)。
但是,外壳程序必须对其脚本具有开放的句柄,并且在
bash的句柄是#255.

##代码##

为我工作。

回答

我想确保脚本在其目录中运行。所以

##代码##

此后,如果我们真的想知道我们在哪里运行,请运行以下命令。

##代码##

回答

这是我发现要可靠地说出的唯一方法:

##代码##

回答

##代码##

回答

dirname命令是最基本的命令,只需从$ 0(脚本名称)变量中解析文件名的路径即可:

##代码##

但是,正如matt b所指出的,根据调用脚本的方式,返回的路径是不同的。 pwd不会执行此操作,因为它只会告诉我们当前目录是什么,而不是脚本所在的目录。此外,如果执行了脚本的符号链接,我们将获得(可能是相对的)路径链接所在的位置,而不是实际的脚本。

其他一些人提到了readlink命令,但是最简单的说,我们可以使用:

##代码##

readlink会将脚本路径解析为从文件系统根目录开始的绝对路径。因此,任何包含单点或者双点,波浪号和/或者符号链接的路径都将解析为完整路径。

这是一个脚本,展示了其中的每一个whatdir.sh:

##代码##

使用相对路径在我的主目录中运行此脚本:

##代码##

同样,但使用脚本的完整路径:

##代码##

现在更改目录:

##代码##

最后使用符号链接执行脚本:

##代码##

回答

##代码##

回答

对解决方案e-satis和3bcdnlklvc04a的略微修改指出了他们的答案

##代码##

在他们列出的所有情况下,这仍然应该起作用。

编辑:阻止失败后弹出,多亏了konsolebox

回答

我尝试了所有这些方法,但没有一个起作用。一个非常接近,但是有一个很小的错误将其严重破坏了。他们忘记将路径用引号引起来。

也有很多人认为我们是从Shell运行脚本的,因此在打开新脚本时会忘记它默认为家。

尝试以下目录获取大小:

/ var /没有人/没有想法/关于空格正在/目录中/名称/这是file.text

不管我们如何运行或者在何处运行,它都可以正确实现。

##代码##

因此,要使其真正有用,这里是如何更改正在运行的脚本的目录:

##代码##

希望能有所帮助

回答

这些都不适用于Finder在OS X中启动的bash脚本,我最终使用了:

##代码##

不漂亮,但是可以完成工作。

回答

##代码##

回答

使用readlink规范化名称(如果是符号链接,则可以将其跟随其名称返回源)和dirname组合以提取目录名称:

##代码##

回答

这将在Mac OS X 10.6.6上获取当前的工作目录:

##代码##