我怎么得到的路的目录中的哪一个 Bash 脚本是的位置, 内部 那剧本吗?

例如,我们说,我想用一个Bash脚本作为一个发射器为另一种应用程序。我想改变工作目录到一个在庆典的脚本,这样我就可以操作的文件,该目录是这样的:

$ ./application
有帮助吗?

解决方案

#!/bin/bash

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"

是一个有用的一个衬垫,这将给你的完整目录名称的脚,无论它被称作。

它将作为长作为最后一个组成部分使用的路径,以找到脚本不是个连接(目录链接是确定)。如果你还想要解决任何链接的脚本本身,需要一个多行的解决方案:

#!/bin/bash

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 2>&1 && 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 2>&1 && pwd )"

这最后一个会工作的任何组合的别名, source, bash -c,链接,等等。

要注意:如果你 cd 到不同的目录之前,运行这一段,结果可能是错误!

此外,观看了 $CDPATH 陷阱, 和stderr输出副作用,如果用户有巧妙地复盖cd重新输出到stderr替代(包括逃序列,例如打电话时 update_terminal_cwd >&2 对Mac)。加入 >/dev/null 2>&1 在结束你的 cd 命令将采取的两种可能性。

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

#!/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" )" >/dev/null 2>&1 && 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'

其他提示

使用 dirname "$0":

#!/bin/bash
echo "The script you are running has basename `basename "$0"`, dirname `dirname "$0"`"
echo "The present working directory is `pwd`"

使用 pwd 不会工作如果你不是在运行的脚本目录所载。

[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命令是最基本的、简单的分析路径的文件断的0美元(脚本名)变量:

dirname "$0"

但是,正如 马特b 指出,路径返回是不同的,取决于如何脚本。pwd不做的工作,因为这只会告诉你什么是当前的目录,而不是目录的脚本所在。此外,如果一个象征性的链接的脚本是执行,你会得到一(可能是相对的)路径链接驻留,并不实际的脚本。

一些其他人所说的 readlink 命令,但在其最简单的,你可以使用:

dirname "$(readlink -f "$0")"

readlink将解决脚本路径的一个绝对的道路的根本文件系统。因此,任何路径含有单一或双点,波浪线和/或象征性的联系将是解决一个全面的路径。

这里有一个脚本,表明每个这些, whatdir.sh:

#!/bin/bash
echo "pwd: `pwd`"
echo "\$0: $0"
echo "basename: `basename $0`"
echo "dirname: `dirname $0`"
echo "dirname/readlink: $(dirname $(readlink -f $0))"

运行这个脚本我的家dir,使用相对路径:

>>>$ ./whatdir.sh 
pwd: /Users/phatblat
$0: ./whatdir.sh
basename: whatdir.sh
dirname: .
dirname/readlink: /Users/phatblat

再次,但是使用的完整的路径脚本:

>>>$ /Users/phatblat/whatdir.sh 
pwd: /Users/phatblat
$0: /Users/phatblat/whatdir.sh
basename: whatdir.sh
dirname: /Users/phatblat
dirname/readlink: /Users/phatblat

现在改变目录:

>>>$ cd /tmp
>>>$ ~/whatdir.sh 
pwd: /tmp
$0: /Users/phatblat/whatdir.sh
basename: whatdir.sh
dirname: /Users/phatblat
dirname/readlink: /Users/phatblat

最后使用象征性的链接到执行。

>>>$ ln -s ~/whatdir.sh whatdirlink.sh
>>>$ ./whatdirlink.sh 
pwd: /tmp
$0: ./whatdirlink.sh
basename: whatdirlink.sh
dirname: .
dirname/readlink: /Users/phatblat
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

适用于所有的版本,其中包括

  • 当时称为过多的深度软链接,
  • 当它文件
  • 脚本时称为通过命令"source"aka . (dot)的操作员。
  • 当arg $0 被修改从来电。
  • "./script"
  • "/full/path/to/script"
  • "/some/path/../../another/path/script"
  • "./some/folder/script"

或者,如果bash脚本本身就是一个 相对symlink 你的 按照它和退回全路径的链接的脚本:

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

SCRIPT_PATH 给出了完整的路径,无论如何它被称为。
只要确定你找到这一点,在开始脚本。

这个评论并代码Copyleft,可选择的许可证下的GPL2.0时或之后或CC-SA3.0(CreativeCommons分享一样)或后。(c)2008年。保留所有权利。没有任何形式的担保。你已经被警告。
http://www.gnu.org/licenses/gpl-2.0.txt
http://creativecommons.org/licenses/by-sa/3.0/
18eedfe1c99df68dc94d4a94712a71aaa8e1e9e36cacf421b9463dd2bbaa02906d0d6656

简短的回答:

`dirname $0`

或者(优选的):

$(dirname "$0")

你可以使用$BASH_SOURCE

#!/bin/bash

scriptdir=`dirname "$BASH_SOURCE"`

注意,你需要使用#!/bin/bash和不#!/bin/sh因为它是一个扩展bash

这应该这样做:

DIR=$(dirname "$(readlink -f "$0")")

与链接和间在路径。见人页 dirnamereadlink.

编辑:

从评论道,它似乎不到工作Mac OS。我不知道为什么,是。任何建议?

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

但是, dirname 给出精确的目录部分的文件,其中更有可能不会相对于目前的工作目录。如果你的脚本需要更改目录由于某些原因,然后再输出 dirname 变得毫无意义的。

我建议如下:

#!/bin/bash

reldir=`dirname $0`
cd $reldir
directory=`pwd`

echo "Directory is $directory"

这样一来,你会得到一个绝对的,而不是相对目录。

由于脚本将运行在一个独立庆典的实例,也没有必要恢复工作的目录之后,但是如果你想变回你的剧本对于一些原因,你可以很容易地分配的价值 pwd 以一个可变之前更改目录,以供将来使用。

虽然只是

cd `dirname $0`

解决了特定方案在这个问题,我找到具有绝对路径要更多的更有用。

我不认为这是作为容易,因为其他人已经逃了出来。密码不起作用,因为目前的dir不一定是目录的脚本。0美元并不总是必须的信息。请考虑以下三种方式引用一个脚本。

./script

/usr/bin/script

script

在第一和第三方式0美元没有完整的路径的信息。在第二和第三,pwd不工作。只有这样,才能得到dir在第三种办法是运行过的路径,找到该文件与正确的匹配。基本上,该守则将不得不重做什么操作系统。

一种方式做什么你都要求将只是硬编码数据在/usr/share dir,并参照它通过完整的路径。数据千万别是在/usr/bin dir无论如何,所以这可能是事情要做。

SCRIPT_DIR=$( cd ${0%/*} && pwd -P )

这得到对目前工作上的目录Mac OS X10.6.6:

DIR=$(cd "$(dirname "$0")"; pwd)
$(dirname "$(readlink -f "$BASH_SOURCE")")

我厌倦了来到这个页面过于复制贴的一个-衬里的接受的答案。问题是它是不容易理解和记忆。

这里是一个容易记住脚本:

DIR=$(dirname "${BASH_SOURCE[0]}")  # get the directory name
DIR=$(realpath "${DIR}")    # resolve its full path if need be

这是Linux具体,但是你可以使用:

SELF=$(readlink /proc/$$/fd/255)

这里是一个POSIX符合一衬:

SCRIPT_PATH=`dirname "$0"`; SCRIPT_PATH=`eval "cd \"$SCRIPT_PATH\" && pwd"`

# test
echo $SCRIPT_PATH

我试过每一个这些并没有把工作。一个非常接近,但有一个小小的错误,打破了它严重;他们忘了包装的路径在引号中。

也有很多人以为你的脚从一个壳所以忘了,当你打开一个新的脚它默认对您的家。

试试这个目录上的大小:

/var/无一认为/关于空间/目录/名称/这里是你的文件。文本

这得到它,无论怎么或在哪里运行。

#!/bin/bash
echo "pwd: `pwd`"
echo "\$0: $0"
echo "basename: `basename "$0"`"
echo "dirname: `dirname "$0"`"

因此,为了使它实际上是有用的,这里是如何改变目录正在运行的脚本:

cd "`dirname "$0"`"

希望帮助

这里是简单的,正确的方式:

actual_path=$(readlink -f "${BASH_SOURCE[0]}")
script_dir=$(dirname "$actual_path")

说明:

  • ${BASH_SOURCE[0]} -完整的路径向脚本。这将是正确的,甚至当的脚本来源,例如 source <(echo 'echo $0') 印刷品 bash, 同时替换 ${BASH_SOURCE[0]} 将打印的全路径的剧本。(当然,这是假设你确定把依赖!)

  • readlink -f -递归的方式解决任何链接在指定的路径。这是一个GNU扩展,而不适用于(例如)BSD系统。如果你正在运行一个Mac,你可以使用的自制要安装GNU coreutils 和取代这一用 greadlink -f.

  • 当然 dirname 得到父目的的路径。

我会用这样的事情:

# retrieve the full pathname of the called script
scriptPath=$(which $0)

# check whether the path is a link or not
if [ -L $scriptPath ]; then

    # it is a link then retrieve the target path and get the directory name
    sourceDir=$(dirname $(readlink -f $scriptPath))

else

    # otherwise just get the directory name of the script path
    sourceDir=$(dirname $scriptPath)

fi

轻微修改,以解决电子赛帝和3bcdnlklvc04a指出 他们的回答

SCRIPT_DIR=''
pushd "$(dirname "$(readlink -f "$BASH_SOURCE")")" > /dev/null && {
    SCRIPT_DIR="$PWD"
    popd > /dev/null
}    

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

编辑:防止popd失败后on,感谢konsolebox

#!/bin/sh
PRG="$0"

# need this for relative symlinks
while [ -h "$PRG" ] ; do
   PRG=`readlink "$PRG"`
done

scriptdir=`dirname "$PRG"`

$_ 值得一提的是作为一种替代0元。如果你正在运行一个脚本,从庆典,接受的答案,可以缩短:

DIR="$( dirname "$_" )"

注意,这是第一次发言,在你的脚本。

我已经比较多的答复,并提出了一些更紧凑的解决方案。这些似乎处理的所有疯狂的边缘情况下出现的从你最喜欢的组合:

  • 绝对或相对路径的路径
  • 文件和目录软链接
  • 援引作为 script, bash script, bash -c script, source script, 或 . script
  • 空间,标签,新行,unicode,等等。在目录和/或文件
  • 文件名开始一个连字符

如果你的运行Linux,它似乎使用 proc 处理是最佳的解决方案找到全面解决来源的目前运行的脚本(在一个交互式的会议,该链接的点对各自的 /dev/pts/X):

resolved="$(readlink /proc/$$/fd/255 && echo X)" && resolved="${resolved%$'\nX'}"

这有一个小一点的丑陋到它,但是修复是紧凑的,并容易理解。我们不是用来砸元,但我没关系因为 readlink 简化了的任务相当。的 echo X 增加了一个 X 结束变量串因此,任何结尾的空白空间中的文件不会得到食用,和参数取代 ${VAR%X} 在结束行摆脱的 X.因 readlink 增加一个新行其自己的(通常被吃掉的命令取代,如果不对我们以前欺骗),我们必须摆脱这一点。这是最容易完成的使用 $'' 引用的方案,这让我们使用逃生顺序,例如 \n 代表新行(这也是你怎么可以很容易地使迂回的命名目录和文件)。

上述应该包括你的需要的定位当前正在运行在Linux,但是如果你没有 proc 文件在您的处置,或者如果你想要找到完全解决的道路的其他一些文件,那么也许你会找到下面的代码有帮助的。这只是一个微小的修改上述一衬里。如果你在玩奇怪的目录/文件,检查出与这两个 lsreadlink 是内容丰富,作为 ls 将输出的"简化"路径,替换 ? 喜欢的事情换行。

absolute_path=$(readlink -e -- "${BASH_SOURCE[0]}" && echo x) && absolute_path=${absolute_path%?x}
dir=$(dirname -- "$absolute_path" && echo x) && dir=${dir%?x}
file=$(basename -- "$absolute_path" && echo x) && file=${file%?x}

ls -l -- "$dir/$file"
printf '$absolute_path: "%s"\n' "$absolute_path"

尝试使用:

real=$(realpath $(dirname $0))

对系统具有使用下载管理器,各种文件下载readlink(eg.linux):

$(readlink -f "$(dirname "$0")")

没有必要使用 BASH_SOURCE$0 含有剧本文件。

所以...我相信我有这一个。迟到的缔约方,但我认为一些会欣赏它在这里是他们遇到的这个线程。评论应当解释。

#!/bin/sh # dash bash ksh # !zsh (issues). G. Nixon, 12/2013. Public domain.

## 'linkread' or 'fullpath' or (you choose) is a little tool to recursively
## dereference symbolic links (ala 'readlink') until the originating file
## is found. This is effectively the same function provided in stdlib.h as
## 'realpath' and on the command line in GNU 'readlink -f'.

## Neither of these tools, however, are particularly accessible on the many
## systems that do not have the GNU implementation of readlink, nor ship
## with a system compiler (not to mention the requisite knowledge of C).

## This script is written with portability and (to the extent possible, speed)
## in mind, hence the use of printf for echo and case statements where they
## can be substituded for test, though I've had to scale back a bit on that.

## It is (to the best of my knowledge) written in standard POSIX shell, and
## has been tested with bash-as-bin-sh, dash, and ksh93. zsh seems to have
## issues with it, though I'm not sure why; so probably best to avoid for now.

## Particularly useful (in fact, the reason I wrote this) is the fact that
## it can be used within a shell script to find the path of the script itself.
## (I am sure the shell knows this already; but most likely for the sake of
## security it is not made readily available. The implementation of "$0"
## specificies that the $0 must be the location of **last** symbolic link in
## a chain, or wherever it resides in the path.) This can be used for some
## ...interesting things, like self-duplicating and self-modifiying scripts.

## Currently supported are three errors: whether the file specified exists
## (ala ENOENT), whether its target exists/is accessible; and the special
## case of when a sybolic link references itself "foo -> foo": a common error
## for beginners, since 'ln' does not produce an error if the order of link
## and target are reversed on the command line. (See POSIX signal ELOOP.)

## It would probably be rather simple to write to use this as a basis for
## a pure shell implementation of the 'symlinks' util included with Linux.

## As an aside, the amount of code below **completely** belies the amount
## effort it took to get this right -- but I guess that's coding for you.

##===-------------------------------------------------------------------===##

for argv; do :; done # Last parameter on command line, for options parsing.

## Error messages. Use functions so that we can sub in when the error occurs.

recurses(){ printf "Self-referential:\n\t$argv ->\n\t$argv\n" ;}
dangling(){ printf "Broken symlink:\n\t$argv ->\n\t"$(readlink "$argv")"\n" ;}
errnoent(){ printf "No such file: "$@"\n" ;} # Borrow a horrible signal name.

# Probably best not to install as 'pathfull', if you can avoid it.

pathfull(){ cd "$(dirname "$@")"; link="$(readlink "$(basename "$@")")"

## 'test and 'ls' report different status for bad symlinks, so we use this.

 if [ ! -e "$@" ]; then if $(ls -d "$@" 2>/dev/null) 2>/dev/null;  then
    errnoent 1>&2; exit 1; elif [ ! -e "$@" -a "$link" = "$@" ];   then
    recurses 1>&2; exit 1; elif [ ! -e "$@" ] && [ ! -z "$link" ]; then
    dangling 1>&2; exit 1; fi
 fi

## Not a link, but there might be one in the path, so 'cd' and 'pwd'.

 if [ -z "$link" ]; then if [ "$(dirname "$@" | cut -c1)" = '/' ]; then
   printf "$@\n"; exit 0; else printf "$(pwd)/$(basename "$@")\n"; fi; exit 0
 fi

## Walk the symlinks back to the origin. Calls itself recursivly as needed.

 while [ "$link" ]; do
   cd "$(dirname "$link")"; newlink="$(readlink "$(basename "$link")")"
   case "$newlink" in
    "$link") dangling 1>&2 && exit 1                                       ;;
         '') printf "$(pwd)/$(basename "$link")\n"; exit 0                 ;;
          *) link="$newlink" && pathfull "$link"                           ;;
   esac
 done
 printf "$(pwd)/$(basename "$newlink")\n"
}

## Demo. Install somewhere deep in the filesystem, then symlink somewhere 
## else, symlink again (maybe with a different name) elsewhere, and link
## back into the directory you started in (or something.) The absolute path
## of the script will always be reported in the usage, along with "$0".

if [ -z "$argv" ]; then scriptname="$(pathfull "$0")"

# Yay ANSI l33t codes! Fancy.
 printf "\n\033[3mfrom/as: \033[4m$0\033[0m\n\n\033[1mUSAGE:\033[0m   "
 printf "\033[4m$scriptname\033[24m [ link | file | dir ]\n\n         "
 printf "Recursive readlink for the authoritative file, symlink after "
 printf "symlink.\n\n\n         \033[4m$scriptname\033[24m\n\n        "
 printf " From within an invocation of a script, locate the script's "
 printf "own file\n         (no matter where it has been linked or "
 printf "from where it is being called).\n\n"

else pathfull "$@"
fi

试试下面兼容的方案:

CWD="$(cd -P -- "$(dirname -- "$0")" && pwd -P)"

作为 realpathreadlink 命令并不总是可用的(根据不同的操作系统), ${BASH_SOURCE[0]} 仅在bash.

或者你可以尝试下列功能击:

realpath () {
  [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"
}

这个函数,需要1个参数。如果参数已经绝对的道路,它打印,因为它是,其他印刷品 $PWD 变+filename argument(没有 ./ 前缀)。

相关:

嗯,如果在道路basename&dirname是只是不会切断它 而走的道路是艰难(如果父母没有出路!).然而,壳已经有一个开放的手把它的脚本,并在 抨击把手#255.

SELF=`readlink /proc/$$/fd/255`

对我的作品。

总的来说,许多答复:

    Script: "/tmp/src dir/test.sh"
    Calling folder: "/tmp/src dir/other"

使用的命令

    echo Script-Dir : `dirname "$(realpath $0)"`
    echo Script-Dir : $( cd ${0%/*} && pwd -P )
    echo Script-Dir : $(dirname "$(readlink -f "$0")")
    echo
    echo Script-Name : `basename "$(realpath $0)"`
    echo Script-Name : `basename $0`
    echo
    echo Script-Dir-Relative : `dirname "$BASH_SOURCE"`
    echo Script-Dir-Relative : `dirname $0`
    echo
    echo Calling-Dir : `pwd`

输出:

     Script-Dir : /tmp/src dir
     Script-Dir : /tmp/src dir
     Script-Dir : /tmp/src dir

     Script-Name : test.sh
     Script-Name : test.sh

     Script-Dir-Relative : ..
     Script-Dir-Relative : ..

     Calling-Dir : /tmp/src dir/other

看看 https://pastebin.com/J8KjxrPF

这一工作在bash-3.2:

path="$( dirname "$( which "$0" )" )"

这里有一个例子,其用途:

说你有一个 ~/bin 目录,这是在你 $PATH.你有脚本 一个 这里面的目录。它的 来源s脚本 ~/bin/lib/B.你知道在哪里包括脚本是相对于原始人(子目录 lib),而不是它被相对用户当前的目录。

这是解决以下(内部 一个):

source "$( dirname "$( which "$0" )" )/lib/B"

不管这里的用户或他如何呼吁脚本,这将一直工作。

没有这些工作的一个庆典脚本推出了由查找器在OS X-我结束了使用:

SCRIPT_LOC="`ps -p $$ | sed /PID/d | sed s:.*/Network/:/Network/: |
sed s:.*/Volumes/:/Volumes/:`"

不很漂亮,但它得到完成工作。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top