基本上我需要使用与shell脚本文件位置相关的路径运行脚本,如何将当前目录更改为脚本文件所在的目录?
The*_*rko 521
在Bash中,你应该得到你需要的东西:
#!/usr/bin/env bash
BASEDIR=$(dirname "$0")
echo "$BASEDIR"
Run Code Online (Sandbox Code Playgroud)
小智 376
原始帖子包含解决方案(忽略响应,他们不添加任何有用的东西).有趣的工作是通过提到的readlink
带有选项的unix命令完成的-f
.当脚本由绝对路径和相对路径调用时工作.
对于bash,sh,ksh:
#!/bin/bash
# Absolute path to this script, e.g. /home/user/bin/foo.sh
SCRIPT=$(readlink -f "$0")
# Absolute path this script is in, thus /home/user/bin
SCRIPTPATH=$(dirname "$SCRIPT")
echo $SCRIPTPATH
Run Code Online (Sandbox Code Playgroud)
对于tcsh,csh:
#!/bin/tcsh
# Absolute path to this script, e.g. /home/user/bin/foo.csh
set SCRIPT=`readlink -f "$0"`
# Absolute path this script is in, thus /home/user/bin
set SCRIPTPATH=`dirname "$SCRIPT"`
echo $SCRIPTPATH
Run Code Online (Sandbox Code Playgroud)
另见:https://stackoverflow.com/a/246128/59087
Dan*_*iel 51
之前对答案的评论说,但在所有其他答案中很容易错过.
使用bash时:
echo this file: "$BASH_SOURCE"
echo this dir: "$(dirname "$BASH_SOURCE")"
Run Code Online (Sandbox Code Playgroud)
Mez*_*Mez 39
假设你正在使用bash
#!/bin/bash
current_dir=$(pwd)
script_dir=$(dirname $0)
echo $current_dir
echo $script_dir
Run Code Online (Sandbox Code Playgroud)
该脚本应该打印您所在的目录,然后目录中的脚本是,例如,从调用它时/
与脚本/home/mez/
,它输出
/
/home/mez
Run Code Online (Sandbox Code Playgroud)
请记住,在从命令输出中分配变量时,将命令包装在- $(
和)
- 或者您将无法获得所需的输出.
doc*_*hat 31
如果你正在使用bash ....
#!/bin/bash
pushd $(dirname "${0}") > /dev/null
basedir=$(pwd -L)
# Use "pwd -P" for the path without links. man bash for more info.
popd > /dev/null
echo "${basedir}"
Run Code Online (Sandbox Code Playgroud)
ran*_*alo 19
正如马科所说:
BASEDIR=$(dirname $0)
echo $BASEDIR
Run Code Online (Sandbox Code Playgroud)
除非您从脚本所在的同一目录执行脚本,否则这将起作用,在这种情况下,您将获得值"."
要解决该问题,请使用:
current_dir=$(pwd)
script_dir=$(dirname $0)
if [ $script_dir = '.' ]
then
script_dir="$current_dir"
fi
Run Code Online (Sandbox Code Playgroud)
您现在可以在整个脚本中使用变量current_dir来引用脚本目录.但是,这可能仍然存在符号链接问题.
Ale*_*ira 17
这里回答了这个问题的最佳答案:
从内部获取Bash脚本的源目录
并且是:
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
Run Code Online (Sandbox Code Playgroud)
One-liner将为您提供脚本的完整目录名称,无论它在何处被调用.
要了解它是如何工作的,您可以执行以下脚本:
#!/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'"
Run Code Online (Sandbox Code Playgroud)
让它成为POSIX oneliner:
a="/$0"; a=${a%/*}; a=${a#/}; a=${a:-.}; BASEDIR=$(cd "$a"; pwd)
Run Code Online (Sandbox Code Playgroud)
测试了许多与Bourne兼容的shell,包括BSD.
据我所知,我是作者,我将其置于公共领域.有关详细信息,请参阅:https: //www.jasan.tk/posts/2017-05-11-posix_shell_dirname_replacement/
小智 8
BASE_DIR="$(cd "$(dirname "$0")"; pwd)";
echo "BASE_DIR => $BASE_DIR"
Run Code Online (Sandbox Code Playgroud)
这个单行说明了 shell 脚本的位置,无论您是运行它还是获取它都无关紧要。此外,它会解析所涉及的任何符号链接,如果是这样的话:
dir=$(dirname $(test -L "$BASH_SOURCE" && readlink -f "$BASH_SOURCE" || echo "$BASH_SOURCE"))
Run Code Online (Sandbox Code Playgroud)
顺便说一句,我想您正在使用/bin/bash。
介绍
这个答案纠正了这个线程(由TheMarko编写)的非常破碎但令人震惊的最高投票答案:
#!/usr/bin/env bash
BASEDIR=$(dirname "$0")
echo "$BASEDIR"
Run Code Online (Sandbox Code Playgroud)
为什么在自己的目录上不能使用目录名“ $ 0”?
dirname $ 0仅在用户以非常特定的方式启动脚本时才有效。我能够找到几种情况,其中该答案失败并导致脚本崩溃。
首先,让我们了解此答案的工作原理。他通过执行来获取脚本目录
dirname "$0"
Run Code Online (Sandbox Code Playgroud)
$ 0代表调用脚本的命令的第一部分(基本上是没有参数的输入命令:
/some/path/./script argument1 argument2
Run Code Online (Sandbox Code Playgroud)
$ 0 =“ / some / path /./ script”
dirname基本上在字符串中找到最后一个/并将其截断。因此,如果您这样做:
dirname /usr/bin/sha256sum
Run Code Online (Sandbox Code Playgroud)
您将获得:/ usr / bin
此示例运行良好,因为/ usr / bin / sha256sum是格式正确的路径,但
dirname "/some/path/./script"
Run Code Online (Sandbox Code Playgroud)
效果不好,会给您:
BASENAME="/some/path/." #which would crash your script if you try to use it as a path
Run Code Online (Sandbox Code Playgroud)
假设您与脚本位于同一目录,并使用此命令启动它
./script
Run Code Online (Sandbox Code Playgroud)
$ 0在这种情况下将是./script和目录名$ 0将给出:
. #or BASEDIR=".", again this will crash your script
Run Code Online (Sandbox Code Playgroud)
使用方法:
sh script
Run Code Online (Sandbox Code Playgroud)
如果不输入完整路径,还将给出BASEDIR =“。
使用相对目录:
../some/path/./script
Run Code Online (Sandbox Code Playgroud)
给出$ 0的目录名:
../some/path/.
Run Code Online (Sandbox Code Playgroud)
如果您位于/ some目录中,并且以这种方式调用脚本(请注意开头没有/,还是相对路径):
path/./script.sh
Run Code Online (Sandbox Code Playgroud)
您将获得目录名$ 0的以下值:
path/.
Run Code Online (Sandbox Code Playgroud)
和./path /./ script(相对路径的另一种形式)给出:
./path/.
Run Code Online (Sandbox Code Playgroud)
basedir $ 0只能工作的两种情况是用户使用sh或touch启动脚本,因为这两种情况都将导致$ 0:
$0=/some/path/script
Run Code Online (Sandbox Code Playgroud)
这将为您提供可与目录名一起使用的路径。
解决方案
您需要考虑并检测上述每种情况,并在出现这种情况时对其进行修复:
#!/bin/bash
#this script will only work in bash, make sure it's installed on your system.
#set to false to not see all the echos
debug=true
if [ "$debug" = true ]; then echo "\$0=$0";fi
#The line below detect script's parent directory. $0 is the part of the launch command that doesn't contain the arguments
BASEDIR=$(dirname "$0") #3 situations will cause dirname $0 to fail: #situation1: user launches script while in script dir ( $0=./script)
#situation2: different dir but ./ is used to launch script (ex. $0=/path_to/./script)
#situation3: different dir but relative path used to launch script
if [ "$debug" = true ]; then echo 'BASEDIR=$(dirname "$0") gives: '"$BASEDIR";fi
if [ "$BASEDIR" = "." ]; then BASEDIR="$(pwd)";fi # fix for situation1
_B2=${BASEDIR:$((${#BASEDIR}-2))}; B_=${BASEDIR::1}; B_2=${BASEDIR::2}; B_3=${BASEDIR::3} # <- bash only
if [ "$_B2" = "/." ]; then BASEDIR=${BASEDIR::$((${#BASEDIR}-1))};fi #fix for situation2 # <- bash only
if [ "$B_" != "/" ]; then #fix for situation3 #<- bash only
if [ "$B_2" = "./" ]; then
#covers ./relative_path/(./)script
if [ "$(pwd)" != "/" ]; then BASEDIR="$(pwd)/${BASEDIR:2}"; else BASEDIR="/${BASEDIR:2}";fi
else
#covers relative_path/(./)script and ../relative_path/(./)script, using ../relative_path fails if current path is a symbolic link
if [ "$(pwd)" != "/" ]; then BASEDIR="$(pwd)/$BASEDIR"; else BASEDIR="/$BASEDIR";fi
fi
fi
if [ "$debug" = true ]; then echo "fixed BASEDIR=$BASEDIR";fi
Run Code Online (Sandbox Code Playgroud)
如果要获取实际的脚本目录(无论您是使用符号链接还是直接调用脚本),请尝试:
BASEDIR=$(dirname $(realpath "$0"))
echo "$BASEDIR"
Run Code Online (Sandbox Code Playgroud)
这适用于linux和macOS。我看不到有人在这里提起realpath
。不确定这种方法是否有任何缺点。
在macOS上,您需要安装coreutils
才能使用realpath
。例如:brew install coreutils
。
基本版:
dir=$(dirname $0)
Run Code Online (Sandbox Code Playgroud)
如果可以通过 调用该脚本$PATH
,则:
dir=$(dirname $(which $0))
Run Code Online (Sandbox Code Playgroud)
如果脚本可以这样调用:bash script.sh
,那么:
dir=$(dirname $(which $0 2>/dev/null || realpath $0))
Run Code Online (Sandbox Code Playgroud)
如果您感到非常不安全,那么:
dir="$(dirname -- "$(which -- "$0" 2>/dev/null || realpath -- "$0")")"
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
500559 次 |
最近记录: |