跳转至

Shell脚本执行不再受限,不进入所在目录也能成功运行

通过使用dirname命令获取脚本执行时的文件路径,并在脚本中进入该目录,你可以确保无论脚本在哪里执行,都能够找到所需的文件

这种方法可以应用于调用同目录下的其他Shell脚本或使用相对路径访问其他文件的情况

下面通过一个简单的示例来演示这种方法。假设在当前目录下,有一个位于bin目录的名为start.sh的脚本,它需要调用同样位于bin目录的名为other.sh的脚本。可以使用以下代码

# 进入脚本所在的目录
cd $(dirname $0)
# 调用其它脚本
./other.sh

上述代码片段中,$0表示当前脚本被执行时的名称,dirname命令从该名称中获取脚本所在目录,$()表示执行括号内的命令并且获得命令的返回结果。$(dirname $0)将得到该脚本相对于当前目录的相对路径。

因此,无论是在当前目录执行“bin/start.sh”,还是进入bin目录后执行“./start.sh”,脚本都能正常调用到other.sh

还可以进一步优化该方案。如果在其它路径创建了start.sh的符号链接,此时就需要获取该符号链接的目标文件地址。可以使用readlink命令来实现。以下是优化后的代码

# 判断是否为符号链接
ftype=$(ls -l $0|cut -c 1)
if [[ $ftype == l ]];then
  # 如果是符号链接,获取其目标文件地址
  path=$(readlink $0)
else
  # 否则直接使用当前文件路径
  path=$0
fi
# 进入脚本所在的目录
cd $(dirname $path)

不过还有一点需要注意,readlink只是获取它接受的参数指定的符号链接的目标文件,如果该目标文件仍然是一个符号链接,则需要继续使用readlink获取目标文件。

可以将这部分封装成一个函数并递归调用,以下是该函数示例:

# 递归调用readlink获取符号链接的最终目标文件
rrl() {
  ftype=$(ls -l $1|cut -c 1)
  if [[ $ftype == l ]];then
    # 如果是符号链接,递归获取其目标文件地址
    echo $(rrl $(readlink $1))
  else
    # 否则直接使用当前文件路径
    echo $1
  fi
}
# 进入脚本所在的目录
cd $(dirname $(rrl $0))

通过这种方式,可以确保无论是在当前目录执行还是通过符号链接执行,脚本都能正常运行并成功调用或访问预期的文件