Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何从脚本本身中获取Bash脚本的源目录?_Bash_Directory - Fatal编程技术网

如何从脚本本身中获取Bash脚本的源目录?

如何从脚本本身中获取Bash脚本的源目录?,bash,directory,Bash,Directory,如何在脚本中获取脚本所在目录的路径 我想使用Bash脚本作为另一个应用程序的启动程序。我想将工作目录更改为Bash脚本所在的目录,以便对该目录中的文件进行操作,如下所示: $ ./application 使用dirname“$0”: 如果不是从包含脚本的目录中运行脚本,则单独使用pwd将不起作用 [matt@server1 ~]$ pwd /home/matt [matt@server1 ~]$ ./test2.sh The script you are running has basenam

如何在脚本中获取脚本所在目录的路径

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

$ ./application
使用
dirname“$0”

如果不是从包含脚本的目录中运行脚本,则单独使用
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

您可以使用
$BASH\u SOURCE

#!/bin/bash

scriptdir=`dirname "$BASH_SOURCE"`

请注意,您需要使用
#/bin/bash
而不是
#/bin/sh
因为它是Bash扩展。

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

./script

/usr/bin/script

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


一种方法是对
/usr/share
目录中的数据进行硬编码,并按其完整路径进行引用。数据无论如何都不应该在
/usr/bin
目录中,因此这可能就是要做的事情。

pwd
可以用于查找当前工作目录,而
dirname
可以用于查找特定文件的目录(运行的命令是
$0
,因此
dirname$0
应该为您提供当前脚本的目录)

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

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

scriptdir=`dirname "$PRG"`
但是,
dirname
精确地给出了文件名的目录部分,该部分很可能与当前工作目录相关。如果脚本出于某种原因需要更改目录,则
dirname
的输出将变得毫无意义

我建议如下:

#!/bin/bash

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

echo "Directory is $directory"
这样,您将得到一个绝对目录,而不是相对目录

由于脚本将在一个单独的Bash实例中运行,因此以后不需要恢复工作目录,但是如果您确实希望出于某种原因在脚本中进行更改,可以在更改目录之前轻松地将
pwd
的值分配给一个变量,以备将来使用

虽然只是

cd `dirname $0`
cd "`dirname "$0"`"

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

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

SELF=$(readlink /proc/$$/fd/255)
它适用于所有版本,包括

  • 通过多深度软链接调用时
  • 什么时候存档
  • 当脚本被命令“
    源”
    “aka
    (点)操作符调用时
  • 从调用方修改arg
    $0
  • “/script”
  • “/full/path/to/script”
  • “/some/path/。/../other/path/script”
  • “/some/folder/script”
或者,如果Bash脚本本身是一个相对符号链接,则希望遵循它并返回链接到脚本的完整路径:

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\u PATH
以完整路径给出,无论如何调用


只需确保在脚本的开头找到它。

这在Bash 3.2中适用:

path="$( dirname "$( which "$0" )" )"
如果在
$PATH
中有
~/bin
目录,则此目录中有
a
。它源于脚本
~/bin/lib/B
。您知道包含的脚本相对于原始脚本的位置,在
lib
子目录中,但不知道它相对于用户当前目录的位置

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

不管用户在哪里,也不管他/她如何调用脚本。这将始终有效

#!/bin/bash

SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && 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 )"
CWD="$(cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
最后一个将与别名、
源代码、
bash-c
、符号链接等的任意组合一起使用

注意:如果在运行此代码段之前将
cd
转到其他目录,则结果可能不正确

另外,如果用户聪明地覆盖了cd以将输出重定向到stderr,则要注意和stderr输出的副作用(包括转义序列,例如在Mac上调用
update\u terminal\u cwd>&2
时)。在
cd
命令末尾添加
/dev/null 2>&1
将考虑这两种可能性

要了解其工作原理,请尝试运行以下更详细的表单:

#!/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”是指向“sym2/scriptdir.sh”(相对于“.”的相对符号链接
源代码为“./sym2/scriptdir.sh”
DIR./sym2解析为“/home/ubuntu/dotfiles/fo-fo/real/real1/real2”
目录是“/home/ubuntu/dotfiles/fo-fo/real/real1/real2”
简短回答:

`dirname $0`
或():

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

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

其他一些
$(dirname "$0")
dirname "$0"
dirname "$(readlink -f "$0")"
#!/bin/bash
echo "pwd: `pwd`"
echo "\$0: $0"
echo "basename: `basename $0`"
echo "dirname: `dirname $0`"
echo "dirname/readlink: $(dirname $(readlink -f $0))"
SCRIPT_DIR=''
pushd "$(dirname "$(readlink -f "$BASH_SOURCE")")" > /dev/null && {
    SCRIPT_DIR="$PWD"
    popd > /dev/null
}
/var/No one/Thought/About Spaces Being/In a Directory/Name/And Here's your file.text
#!/bin/bash
echo "pwd: `pwd`"
echo "\$0: $0"
echo "basename: `basename "$0"`"
echo "dirname: `dirname "$0"`"
cd "`dirname "$0"`"
SCRIPT_DIR=$( cd ${0%/*} && pwd -P )
DIR=$(cd "$(dirname "$0")"; pwd)
$(dirname "$(readlink -f "$BASH_SOURCE")")
DIR="$( dirname "$_" )"
real=$(realpath $(dirname $0))
# 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
SCRIPT_PATH=`dirname "$0"`; SCRIPT_PATH=`eval "cd \"$SCRIPT_PATH\" && pwd"`

# test
echo $SCRIPT_PATH
resolved="$(readlink /proc/$$/fd/255 && echo X)" && resolved="${resolved%$'\nX'}"
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"
CWD="$(cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
realpath () {
  [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"
}
#!/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
$(readlink -f "$(dirname "$0")")
DIR="$(dirname "$(readlink -f "$0")")"
actual_path=$(readlink -f "${BASH_SOURCE[0]}")
script_dir=$(dirname "$actual_path")
    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
DIR="$(dirname "${BASH_SOURCE[0]}")"  # Get the directory name
DIR="$(realpath "${DIR}")"    # Resolve its full path if need be