できない.dev

Bash で「Permission denied」が出てシェルスクリプトを実行できない

./script.sh が Permission denied になるのは、ファイルに実行ビットが立っていないか、置き場所が noexec でマウントされているかのどちらかである。chmod +x で実行ビットを付けるか、bash script.sh とインタプリタを明示して回避する。

公開:

要約

bash: ./script.sh: Permission denied は、スクリプトを実行しようとしたが実行権が無いときに出る。
文法エラーでもインタプリタの不在でもないので、まず ls -l で権限を見るのが最短である。

$ ./deploy.sh
bash: ./deploy.sh: Permission denied
$ ls -l deploy.sh
-rw-r--r-- 1 user user 512 Aug 10 09:00 deploy.sh

-rw-r--r--x が無い。
この状態でスクリプト名を直接叩くと、カーネルの execveEACCES を返し、Bash がそれを Permission denied として表示する。
終了ステータスは 126 になる。

よくある原因

  1. 実行ビットが立っていない: 一番多い。git clone した直後、unzip で展開した直後、Windows 側のエディタで作った直後などに起きる。
  2. #! 行のインタプリタ側に実行権が無い: スクリプトには x があるのに落ちる場合はこちらを疑う。
  3. 置き場所が noexec: /tmpnoexec でマウントしている環境や、外部メディア・一部のコンテナでは、実行ビットがあっても実行できない。
  4. 親ディレクトリに検索権が無い: ディレクトリの x はそこを通り抜ける権限を意味する。
    これが無いとファイルへ到達できない。
  5. 所有者が自分ではない: sudo を付けて展開・コピーした結果、root 所有の -rwx------ になっていると、自分では実行できない。

なお ./dir のようにディレクトリを実行しようとした場合は Is a directory になり、このエラーにはならない。
メッセージが Permission denied であるうちは、上の 5 つのいずれかである。

解決策

1. 実行ビットを付ける

ls -l deploy.sh              # 所有者が自分か、x があるかを見る
chown "$USER" deploy.sh      # 所有者が違うときだけ
chmod +x deploy.sh
./deploy.sh

+x は所有者・グループ・その他のすべてに実行権を足す(chmod の仕様(新しいタブで開く))。
自分だけに限定したいなら chmod u+x deploy.sh を使う。

2. 権限を変えずに実行する

bash deploy.sh
sh deploy.sh        # POSIX sh として動かしたい場合

インタプリタを明示すると、実行されるのは bash であってスクリプトファイルではないため、実行ビットが無くても動く。
読み取り権さえあればよい。
noexec なディレクトリでも通る。

3. noexec を確認する

mount | grep -E ' /tmp | on /mnt'

出力に noexec があれば、そこに置いたスクリプトは実行ビットがあっても実行できない。
ホームディレクトリなど別の場所へ移す。

4. 実行ビットを Git に記録する

git update-index --chmod=+x deploy.sh
git commit -m "make deploy.sh executable"

ローカルで chmod しても、実行ビットを commit していなければ他の開発者や CI では再び Permission denied になる。
Bash スクリプトをリポジトリに置くときはここまでやっておく。

この記事は役立ちましたか?