6277

如何获取目录的路径猛击脚本位于,里面那个脚本?

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

$ ./应用
5
  • 92
    如果存在任何解决方案,则当前的解决方案都不起作用目录名末尾的换行-他们将被命令替换掉。要解决这个问题,可以在命令替换中附加一个非换行字符-DIR=“$(cd”$(目录名“${BASH_SOURCE[0]}”)“&&pwd&&echo x)”-并在不替换命令的情况下删除它-DIR=“${DIR%x}”.
    – 10亿
    评论 2012年9月24日12:15
  • 97
    @jpmc26有两种非常常见的情况:事故和破坏。脚本不应该仅仅因为某人在某处执行了mkdir$“\n”.
    – 10亿
    评论 2013年3月28日8:14
  • 38
    任何让人们以这种方式破坏他们的系统的人都不应该让它去检测这样的问题。。。更不用说雇佣有能力犯这种错误的人了。在使用bash的25年中,我从未见过这种事情在任何地方发生。。。。这就是为什么我们有像perl这样的东西和像污点检查这样的实践(我可能会因为这样说而感到愤怒:) 评论 2015年2月5日0:12
  • 86
    我强烈建议读这篇文章Bash常见问题关于主题。 评论 2016年1月30日2:22
  • @osirisgothra任何认为解决文件名中危险字符的方法不是编写健壮的脚本,而是阻止人们(可能在某些时候创建危险名称)访问系统的人都会遇到困难。
    – 街童
    评论 5月3日4:15

77个答案77

重置为默认值
0

您可以通过follow short方式从脚本内部获取Bash脚本的源目录:

script_path=$(目录名“$(readlink-f”$0“)”)“/”echo“$script_path”

样本输出:

/主页/用户名/桌面/
-1
函数getScriptAbsoluteDir{#fold>>#@description用于获取脚本路径#@param$1脚本$0参数本地script_invoke_path=“$1”local cwd=`pwd`#绝对路径?如果是,第一个字符是/如果测试“x${script_invoke_path:0:1}”='x/'然后结果=`dirname“$script_invoke_path”`其他的结果=`dirname“$cwd/$script_invoke_path”`fi(菲涅耳)}#<<折叠
  • 对不起,我有点像bash scrip noob,我只需键入即可调用此函数吗获取脚本绝对目录local currdir='getScriptAbsoluteDir'?
    – 加亚罗
    评论 2009年11月30日16:04
  • 4
    -1:功能关键字在POSIX shell上不可用,它是一个不必要的不兼容bash/ksh/&c扩展。此外,如果您使用的shell足够新,可以使用该扩展,则不需要测试“x[…]”。 评论 2014年6月9日3:41
  • 这看起来像Python。。。我似乎记不得我曾经在shell脚本中使用过“local”关键字。。。按照查尔斯的说法如果[[“${script_invoke_path:0:1}”==“/”]];然后等等。注意逻辑双精度==“等于”运算符。 评论 2014年9月9日23:31
-1
cur_dir=`old=\`pwd\`;cd \`dirname$0\`;echo \`pwd\`;cd$old`
-1

没有分叉(除了子shell),并且可以处理“外来”路径名形式,如一些人所说的带有换行符的形式:

IFS=读取-rd''DIR<<([[$BASH_SOURCE!=*/*]]||cd“${BASH_SURCE%/*}/”>&&echo-n“$PWD”)
-1

看看底部有奇怪目录名的测试。

要将工作目录更改为Bash脚本所在的目录,您应该尝试以下简单方法:,已测试并通过验证检查外壳解决方案:

#!/垃圾桶/垃圾桶--cd“$(目录名”${0}“)”/.||出口2

测试:

$1ls(美元)应用$mkdir“$(打印文件“\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\46\47testdir”“”)”$mv应用程序*测试目录$ln-s*testdir“$(打印f”\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\41\42\43\44\45\46\47符号链接“”)”$ls-磅总共4个lrwxrwxrwx 1 jay stacko 46 3月30日20:44\001\002\003\004\005\006\a\b\t\n\v\f\r\n016\017\0022\022\ 023\024\025\026\027\030\031\032\034\035\036\037\!“#$%&'symlink->\001\002\003\004\005\006\a\b\t\n\v\f\r\n016\017\020\022\023\024\025\026\027\030\031\032\034\035\036\037\!”#$%&'testdirdrwxr-xr-x 2 jay stacko 4096 3月30日20:44\001\002\003\004\005\006\a\t\n\v\f\r\n016\017\020\022\023\024\026\027\030\031\033\035\036\037\!“#$%&'测试目录$*testdir/application&&printf“成功”成功$*symlink/application&&printf“成功”成功
-1

我通常在脚本顶部包含以下内容,这些内容在大多数情况下都有效:

[“$(目录名$0)”='.']&&SOURCE_DIR=$(pwd)|| SOURCE_DIR=$(目录名$0);ls-l$0|grep-q^l&&SOURCE_DIR=$(ls-l$0 |awk“{print$NF}”);

第一行根据的值分配源密码如果从当前路径运行,或者目录名如果从其他地方打来电话。

第二行检查路径以查看它是否是符号链接,如果是,则将SOURCE_DIR更新到链接本身的位置。

也许有更好的解决方案,但这是我自己想出的最干净的解决方案。

-1

尝试以下操作:

函数get_realpath(){如果[[-f“$1”]]然后#文件*必须*存在如果cd“$(echo“${1%/*}”)”&>/dev/null然后#文件*可能*不是本地文件。#例外情况是/文件.ext#t试用光盘。;cd-;'*奏效了*local tmppwd=“$PWD”cd->/dev/null其他的#文件*必须*为本地文件local tmppwd=“$PWD”fi(菲涅耳)其他的#文件*不能*存在return 1#失败fi(菲涅耳)#重新组装realpathecho“$tmppwd”/“${1#*/}”return 0#成功}函数get_dername(){local realpath=“$(get_realpath”$1“)”if(($?))#非零时为True。然后返回$?#失败fi(菲涅耳)echo“${realpath%/*}”return 0#成功}#然后从顶层开始:get_dirname”/script.sh’#或在脚本中:get_dirname“$0”#甚至可以测试结果!if(($?))#非零时为True。然后退出1#失败fi(菲涅耳)

这些功能和相关工具是我们产品的一部分,社区可以免费使用,可以在GitHub上找到真实路径类它简单、干净、文档记录良好(非常适合学习)、纯Bash且没有依赖性。也适用于跨平台使用。因此,对于上述示例,在脚本中您可以简单地:

源“/path/to/realpath-lib”get_dirname“$0”if(($?))#非零时为True。然后退出1#失败fi(菲涅耳)
-1

关键部分是我正在缩小问题的范围:我禁止通过路径间接执行脚本(如/bin/sh[相对于路径组件的脚本路径]).

可以检测到这一点,因为$0将是一个相对路径,它不会解析为相对于当前文件夹的任何文件。我相信使用#!机制总是导致绝对$0,包括在路径上找到脚本时。

我还要求路径名和符号链接链上的任何路径名只包含合理的字符子集,尤其是不包含\n个,>,*?。这是解析逻辑所必需的。

还有一些更隐含的期望,我不会深入讨论(看这个答案),我不试图处理蓄意破坏$0(因此,请考虑任何安全影响)。我希望这几乎适用于任何具有Bourne风格的类Unix系统/垃圾桶/桶.

#!/垃圾桶/桶(路径=“${0}”测试时-n“${path}”;#确保我们至少有一个斜线,没有前导破折号。expr“${path}”:/>/dev/null|path=“./${path2}”#过滤掉路径名中的错误字符。expr“${path}”:“.*[*?<>\\]”>/dev/null&&exit 1#捕获嵌入的新行和不存在的(或与路径相关的)文件。#通过“#!”调用脚本时,$0应始终是绝对值。test“`ls-l-d”${path}“2>/dev/null|wc-l`”-eq 1||exit 1#更改为包含文件的文件夹以解析相对链接。文件夹=`expr“${path}”:“\(.*/\)[^/][^/]*/*$”`||退出1路径=`expr“x\`ls-l-d”${path}“\`”:“[^>]*->\(.*\)”`cd“${文件夹}”#如果最后一个路径不是链接,则我们位于目标文件夹中。测试-n“${path}”|pwd完成)
-1

这个脚本会导致什么问题?

#!/垃圾桶/垃圾桶x=`哪个“${0}”`echo basename=`basename“${x}”`echo dirname=`dirname“${x}”`回波电流pwd=`pwd`

我把这个脚本放到~/带空格的路径/

$ls-alFd~/p*

drwxr-xr-x 1无0'/home/Asus/path with space'/

测试:

$pwd(加元)/主页/华硕$bash~/path\ with\space/test.shbasename=测试.shdirname=/home/Asus/path,带空格当前密码=/home/Asus$~/path\ with\space/test.shbasename=测试.shdirname=/home/Asus/path,带空格当前密码=/home/Asus$ ./路径\ with\space/test.shbasename=测试.shdirname=/home/Asus/path,带空格当前密码=/home/Asus$巴什/路径\ with\space/test.shbasename=测试.shdirname=/home/Asus/path,带空格当前密码=/home/Asus美元cd/tmp$bash~/path\ with\space/test.shbasename=测试.shdirname=/home/Asus/path,带空格当前pwd=/tmp$~/path\ with\space/test.shbasename=测试.shdirname=/home/Asus/path,带空格当前pwd=/tmp
-2

基于这个答案,我建议澄清版本脚本_主页作为任何当前运行的Bash脚本的包含文件夹:

s=${BASH_SOURCE[0]};s=`dirname$s`;SCRIPT_HOME=`cd$s;密码`echo$SCRIPT_HOME
-3

我想确保脚本正在其目录中运行。所以

cd$(目录名$(其中$0))

在此之后,如果你真的想知道你在哪里运行,那么运行下面的命令。

DIR=$(/usr/bin/pwd)
1
  • 6
    这与其他答案有何不同? 评论 2015年1月20日12:18
-3

这个单层衬里在上工作Cygwin公司即使脚本是从窗户具有bash-c<脚本>:

set mydir=“$(cygpath”$(目录名“$0”)”)
-3

我想评论一下前面的答案(如何从脚本本身中获取Bash脚本的源目录?),但没有足够的声誉来这样做。

两年前,我在苹果的文档网站上找到了一个解决方案:https://developer.apple.com/library/archive/documentation/OpenSource/Conceptual/ShellScripting/AdvancedTechniques/AdvancedTechnixes.html之后我坚持使用这种方法。它无法处理软链接,但其他方面对我来说效果很好。我将其发布在这里,以供任何需要它的人发表评论。

#!/垃圾桶/桶#获取poem.txt文件的绝对路径。POEM=“$PWD/../poement.txt”#获取脚本文件的绝对路径。SCRIPT=“$(其中$0)”如果[“x$(echo$SCRIPT|grep'^\/')”=“x”];然后SCRIPT=“$PWD/$SCRIPT”fi(菲涅耳)

如代码所示,获得脚本的绝对路径后,可以使用目录名命令获取目录的路径。

-4

这是我多年来精心设计的,用作Bash脚本的标题:

##基础大脑-了解你来自哪里,你是谁。我的=$$ORIGINAL_DIR=“$(pwd)”#这不是热气球之旅。。fa=“$0”#第一假设ta=#临时假设wa=#加权假设虽然是真的;[“${fa:0:1}”=“/”]&&wa=$0&&break[“${fa:0:2}”=“./”]&&ta=“${ORIGINAL_DIR}/${fa:2}“&&[-e”$ta“]&wa=“$ta”&&breakta=“${ORIGINAL_DIR}/${fa}”&&[-e“$ta”]&wa=“$ta“&&break完成SW=“$wa”SWDIR=“$(目录名”$wa“)”SWBIN=“$(basename”$wa“)”未设置ta fa wa([!-e“$SWDIR/$SWBIN”]||[-z“$SW”])&&echo“我找不到路:(TOP脚本中可能存在的错误”&&exit 1

此时,变量SW、SWDIR和SWBIN包含您需要的内容。

1
  • 一个很好的代码模糊竞赛候选人。而不是原始_DIR你可以使用PWD公司,以及做什么MYPID公司反正和答案有关吗? 评论 2022年3月25日5:37
-4

没有100%可移植且可靠的方法来请求指向当前脚本目录的路径。特别是在不同的后端之间Cygwin公司,工具链,MSYS公司、Linux等。这个问题在Bash中很长一段时间都没有得到正确和完全的解决。

例如,如果要在来源命令嵌套包含另一个Bash脚本,该脚本反过来使用相同的来源命令以包含另一个Bash脚本等。

如果是来源命令,我建议更换来源命令如下:

函数include(){如果[[-n“$CURRENT_SCRIPT_DIR”]];然后本地目录路径=。。。从`CURRENT_SCRIPT_DIR/$1`获取目录,取决于$1是绝对路径还是相对路径。。。local include_file_path=。。。其他的本地目录路径=。。。使用此处应答的方法之一从“$1”参数请求目录。。。local include_file_path=。。。fi(菲涅耳)…正在将$CURRENT_SCRIPT_DIR推入堆栈。。。export CURRENT_SCRIPT_DIR=。。。使用$dir_path导出当前脚本目录。。。源“$include_file_path”…从堆栈中弹出$CURRENT_SCRIPT_DIR。。。}

从现在起,使用包括(…)基于上一个当前_ CRIPT_DIR在脚本中。

只有当您可以替换所有来源命令依据包括命令。如果你不能,那你就别无选择。至少在Bash解释器的开发人员发出显式命令以请求当前运行的脚本目录路径之前。

我自己最接近的实现:
https://github.com/andry81/stalglelib/tree/HEAD/bash/calglelib/bash_tacklelib

(搜索tkl包含功能)

-6

这个选择的答案效果非常好。我将发布我的解决方案,供任何寻求更短替代方案的人使用,这些替代方案仍然可以解决源代码、执行、完整路径、相对路径和符号链接等问题。最后,这将适用于macOS操作系统,因为不能假设GNU的coreutils版本的readlink(读链接)可用。

问题是它没有使用Bash,但很容易在Bash脚本中使用。虽然OP没有对解决方案的语言设置任何限制,但大多数人最好还是留在Bash世界中。这只是一种选择,可能并不受欢迎。

默认情况下,PHP在macOS上可用,并安装在许多其他平台上,但默认情况下不一定如此。我意识到这是一个缺点,但无论如何,我将把这个留给来自搜索引擎的任何人。

export SOURCE_DIRECTORY=“$(php-r'echo目录名(realpath($argv[1]));'”--“${BASH_SOURCE[0]}”)“
1
  • 问题中没有关于MacOS的任何内容。我认为这个答案应该从“另一种方法是使用PHP而不是BASH”开始。因为这只会在答案的末尾显示出来。 评论 2019年2月24日22:14
-8

保持简单。

#!/usr/bin/env-bashsourceDir=`pwd`echo$sourceDir

不是你想要的答案吗?浏览标记的其他问题问你自己的问题.