0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Shell Scriptの実行ディレクトリを取得する

Last updated at Posted at 2019-10-12

1958年9月の狩野川台風に匹敵する規模台風19号がやってきて、避難命令が発令されたり、河川が溢れたり大変になっています。ラグビーワールドカップの試合も中止になったりと気持ちの面での被害が大きくなっています。

せっかく中心街のアーケード街で買い物でもしようかなと考えていたのに、電車も計画運休で動いていないので、仕方なく部屋でゴソゴソとパソコン触っています。

今回はShell Scriptをどこから呼び出しても、実行スクリプトの絶対パスを取得できる方法をいつも忘れてしまうので、覚書として残しておこうと思います。

環境

$ uname -a
Linux ip-172-26-5-169 4.4.0-1074-aws #84-Ubuntu SMP Thu Dec 6 08:57:58 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
$ cat /etc/issue
Ubuntu 16.04.5 LTS \n \l

Ubuntu 16.04.5 です。

簡単な方法

もし1行で記述する場合は以下の書き方が楽ちんです。

DIR="$( cd "$( dirname "$0" )" >/dev/null 2>&1 && pwd )"
echo "DIR is '$DIR'"

ただし、この方法はディレクトリがSymbolic linkでは対応していません。

シンボリックリンクでも大丈夫な方法

#!/bin/bash

SOURCE="$0"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
  DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"
  SOURCE="$(readlink "$SOURCE")"
  [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
done
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"
echo "DIR is '$DIR'"

だいたいはこのスニペットで大丈夫だと思いますが、もし相対シンボリックリンクも対応したい場合は、下記の方法で取得します。

相対シンボリックパスも大丈夫な方法

#!/bin/sh

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" )" >/dev/null 2>&1 && pwd )"
if [ "$DIR" != "$RDIR" ]; then
  echo "DIR '$RDIR' resolves to '$DIR'"
fi
echo "DIR is '$DIR'"

エイリアス、sourcebash -c、シンボリックリンクなどの任意の組み合わせで動作します。

ただし、このスニペットを実行する前にcdコマンドを利用して別のディレクトリに移動した場合、結果が間違っている可能性がありますので注意してください。

最後に

Ubuntuのデフォルトシェルはbashではなく、dashだったんですね(汗

$ readlink -f $(which sh)
/bin/dash

それを知らなかったので、BASH_SOURCE[0]を使うとBad substitutionと警告が表示されてしまった。

$ sh publish.sh 
publish.sh: 7: publish.sh: Bad substitution

参考

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?