基本上我需要运行与shell脚本文件位置相关的路径脚本,我如何将当前目录更改为脚本文件所在的相同目录?
当前回答
介绍
这个答案纠正了这个帖子(由TheMarko撰写)中非常糟糕但令人震惊的投票结果:
#!/usr/bin/env bash
BASEDIR=$(dirname "$0")
echo "$BASEDIR"
为什么使用dirname "$0"对它自己不工作?
Dirname $0只在用户以非常特定的方式启动脚本时才会工作。我找到了几种这种答案失败并使脚本崩溃的情况。
首先,让我们理解这个答案是如何工作的。他通过做
dirname "$0"
$0表示调用脚本的命令的第一部分(它基本上是没有参数的输入命令:
/some/path/./script argument1 argument2
0美元=剧本-点- path。”
Dirname基本上找到字符串中的最后一个/并在那里截断它。所以如果你这样做:
dirname /usr/bin/sha256sum
你会得到:/usr/bin
这个例子工作得很好,因为/usr/bin/sha256sum是一个格式正确的路径,但是
dirname "/some/path/./script"
不会很好地工作,并且会给你:
BASENAME="/some/path/." #which would crash your script if you try to use it as a path
假设您位于与脚本相同的目录中,并使用以下命令启动它
./script
$0在这种情况下将是./script, dirname $0将给出:
. #or BASEDIR=".", again this will crash your script
使用:
sh script
不输入完整路径也会给出一个BASEDIR="。"
使用相对目录:
../some/path/./script
给出dirname $0的值:
../some/path/.
如果你在/some目录下,你以这种方式调用脚本(注意开头没有/,同样是一个相对路径):
path/./script.sh
你会得到dirname $0的值:
path/.
和。/ /路径。/script(相对路径的另一种形式)给出:
./path/.
只有两种情况下basedir $0将工作:当用户使用sh或touch启动脚本时,因为这两种情况都会导致$0:
$0=/some/path/script
这将为您提供一个可以使用dirname的路径。
解决方案
你必须解释并检测上面提到的每一种情况,并在出现时应用修复程序:
#!/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
其他回答
这应该能奏效:
echo `pwd`/`dirname $0`
它可能看起来很丑,这取决于它是如何被调用和cwd,但应该得到你需要去的地方(或者你可以调整字符串,如果你关心它的外观)。
BASE_DIR="$(cd "$(dirname "$0")"; pwd)";
echo "BASE_DIR => $BASE_DIR"
对于tcsh,您可以使用:h变量修饰符来检索路径。
需要注意的是,如果脚本作为tcsh myscript执行。Csh,那么您将只获得脚本名称。一个解决方法是验证路径,如下所示。
#!/bin/tcsh
set SCRIPT_PATH = $0:h
if ( $SCRIPT_PATH == $0 ) then
set SCRIPT_PATH = "."
endif
$SCRIPT_PATH/compile.csh > $SCRIPT_PATH/results.txt
关于变量修饰语的更多信息可以在https://learnxinyminutes.com/docs/tcsh/上找到
这一行代码告诉shell脚本在哪里,与您是否运行它或是否获取它无关。此外,它还会解析所涉及的任何符号链接,如果是这样的话:
dir=$(dirname $(test -L "$BASH_SOURCE" && readlink -f "$BASH_SOURCE" || echo "$BASH_SOURCE"))
顺便说一下,我认为您正在使用/bin/bash.
最初的帖子包含了解决方案(忽略回复,他们没有添加任何有用的东西)。有趣的工作是由前面提到的unix命令readlink和选项-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
对于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
参见:https://stackoverflow.com/a/246128/59087
推荐文章
- 如何在Makefile中设置子进程的环境变量
- 如何让“wc -l”打印没有文件名的行数?
- 有效地测试Linux上的端口是否打开?
- 如何从另一个文件A中删除文件B中出现的行?
- 对以制表符分隔的文件进行排序
- Shell脚本删除超过n天的目录
- 如何检查shell脚本中是否存在命令?
- 如何使用查找命令从列表中查找所有具有扩展名的文件?
- 如何打破一个循环在Bash?
- 如何将文件指针(file * fp)转换为文件描述符(int fd)?
- 如何合并2 JSON对象从2个文件使用jq?
- 在Bash中获取日期(比当前时间早一天)
- Linux: kill后台任务
- 在OSX中永久设置PATH环境变量
- 删除Bash脚本中的重复条目