我如何找到一个Bash脚本位于该脚本内部的目录的路径?
我想用Bash脚本作为另一个应用程序的启动器,我想将工作目录更改为Bash脚本所在的目录,所以我可以在该目录中的文件上运行,如下:
$ ./application
我如何找到一个Bash脚本位于该脚本内部的目录的路径?
我想用Bash脚本作为另一个应用程序的启动器,我想将工作目录更改为Bash脚本所在的目录,所以我可以在该目录中的文件上运行,如下:
$ ./application
当前回答
pwd 可以用来找到当前工作目录,而 dirname 可以用来找到特定文件的目录(运行命令为 $0,所以 dirname $0 应该给你当前脚本的目录)。
然而,字体名称给出了字体名称的目录部分,这更有可能与当前工作目录无关,如果你的脚本需要因某种原因更改目录,那么字体名称的输出就会变得毫无意义。
我建议如下:
#!/usr/bin/env bash
reldir="$( dirname -- "$0"; )";
cd "$reldir";
directory="$( pwd; )";
echo "Directory is ${directory}";
这样,你就得到一个绝对的,而不是一个相对的目录。
由于脚本将在一个单独的Bash例子中运行,没有必要恢复工作目录后,但如果你想因某种原因改变你的脚本,你可以轻松地将PWD的值分配给一个变量,在你更改目录之前,用于未来的使用。
雖然只是
cd "$( dirname -- "$0"; )";
解决这个问题的具体场景,我发现有绝对的道路到更有用的一般。
其他回答
查看下面的测试与奇怪的目录名称。
要将工作目录更改为Bash脚本的位置,您应该尝试这个简单的,测试和验证的Shellcheck解决方案:
#!/bin/bash --
cd "$(dirname "${0}")"/. || exit 2
测试:
$ ls
application
$ mkdir "$(printf "\1\2\3\4\5\6\7\10\11\12\13\14\15\16\17\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37\40\41\42\43\44\45\46\47testdir" "")"
$ mv application *testdir
$ ln -s *testdir "$(printf "\1\2\3\4\5\6\7\10\11\12\13\14\15\16\17\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37\40\41\42\43\44\45\46\47symlink" "")"
$ ls -lb
total 4
lrwxrwxrwx 1 jay stacko 46 Mar 30 20:44 \001\002\003\004\005\006\a\b\t\n\v\f\r\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\ !"#$%&'symlink -> \001\002\003\004\005\006\a\b\t\n\v\f\r\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\ !"#$%&'testdir
drwxr-xr-x 2 jay stacko 4096 Mar 30 20:44 \001\002\003\004\005\006\a\b\t\n\v\f\r\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\ !"#$%&'testdir
$ *testdir/application && printf "SUCCESS\n" ""
SUCCESS
$ *symlink/application && printf "SUCCESS\n" ""
SUCCESS
这应该是这样做的:
DIR="$(dirname "$(realpath "$0")")"
这与路线上的交线和空间一起工作。
请参见男人的页面为 dirname 和 realpath。
请添加关于如何支持MacOS的评论,对不起,我可以验证。
下面将返回剧本的当前目录
工作,如果它是源,或者不源工作,如果运行在当前的目录,或某些其他目录.工作,如果相对目录被使用.工作与 bash,不确定其他<unk>。
/tmp/a/b/c $ . ./test.sh
/tmp/a/b/c
/tmp/a/b/c $ . /tmp/a/b/c/test.sh
/tmp/a/b/c
/tmp/a/b/c $ ./test.sh
/tmp/a/b/c
/tmp/a/b/c $ /tmp/a/b/c/test.sh
/tmp/a/b/c
/tmp/a/b/c $ cd
~ $ . /tmp/a/b/c/test.sh
/tmp/a/b/c
~ $ . ../../tmp/a/b/c/test.sh
/tmp/a/b/c
~ $ /tmp/a/b/c/test.sh
/tmp/a/b/c
~ $ ../../tmp/a/b/c/test.sh
/tmp/a/b/c
测试.sh
#!/usr/bin/env bash
# snagged from: https://stackoverflow.com/a/51264222/26510
function toAbsPath {
local target
target="$1"
if [ "$target" == "." ]; then
echo "$(pwd)"
elif [ "$target" == ".." ]; then
echo "$(dirname "$(pwd)")"
else
echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"
fi
}
function getScriptDir(){
local SOURCED
local RESULT
(return 0 2>/dev/null) && SOURCED=1 || SOURCED=0
if [ "$SOURCED" == "1" ]
then
RESULT=$(dirname "$1")
else
RESULT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
fi
toAbsPath "$RESULT"
}
SCRIPT_DIR=$(getScriptDir "$0")
echo "$SCRIPT_DIR"
这种方法的一个好处是,它不涉及Bash本身以外的任何东西,也不会破坏任何底层。
首先,使用模式替代替代不以 / (即相对路径) 以 $ PWD/. 因为我们使用替代替代相匹配的第一个字符为 $ 0,我们也必须添加它回来(${0:0:1} 在替代中)。
现在我们有一个完整的路径到脚本;我们可以通过删除最后的 / 和随后的任何东西(即脚本名称)来获得目录。
#!/bin/bash
BIN=${0/#[!\/]/"$PWD/${0:0:1}"}
DIR=${BIN%/*}
cd "$DIR"
如果您的脚本可以源于而不是执行,您可以将 $0 取代 ${BASH_SOURCE[0]},例如:
BIN=${BASH_SOURCE[0]/#[!\/]/"$PWD/${BASH_SOURCE[0]:0:1}"}
这将为可执行的脚本工作,它更长,但更多。
我认为最简单的答案是原始变量的参数扩展:
#!/usr/bin/env bash
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
echo "opt1; original answer: $DIR"
echo ''
echo "opt2; simple answer : ${BASH_SOURCE[0]%/*}"
它应该产生产量如:
$ /var/tmp/test.sh
opt1; original answer: /var/tmp
opt2; simple answer : /var/tmp
变量/参数扩展 ${BASH_SOURCE[0]%/*}”似乎更容易保持。