Python実行時に zsh: permission denied が出る原因まとめ(Mac)


ターミナルで ./hello.py と打ったら zsh: permission denied: ./hello.py が出た、という場合、Python スクリプトを動かしたいだけなら次の形で足ります。

python3 hello.py

python3 に「このファイルを読んで実行して」と渡す形なので、スクリプト側に実行権限は要りません。./hello.py の形にこだわる場合だけ、実行権限と1行目の #!(shebang)の両方が必要になります。片方だけだと、permission denied が別のエラーに変わるだけです。

以下は、このサイトの運営に使っているMac(macOS 26.6.2・zsh 5.9)で、2026年10月19日に /tmp の下へ一時フォルダを作って打った記録です。中身が print("hello") の1行だけの hello.py を使っています。ホームフォルダのパスは ~ に置き換えています。

まず再現:何が起きているか

% ls -l hello.py
-rw-r--r--  1 me  wheel  15 10月 19 00:09 hello.py
% ./hello.py
zsh: permission denied: ./hello.py
% echo $?
126
% python3 hello.py
hello

読み方は次のとおりです。

  • 行の先頭の zsh: は、このメッセージを出したのがシェル(zsh)だという印です。Python はまだ起動していないので、コードの中身は関係ありません。
  • ls -l の左端 -rw-r--r-- は、1文字目が種類(- は普通のファイル)、次の3文字 rw- が持ち主の権限です。x(実行)が無いので、./ で「プログラムとして起動」できません。
  • echo $? の 126 は「見つかったが実行できなかった」という終了コードです。

似た表示との区別も試しました。./ を付けずに hello.py とだけ打つと、シェルは PATH の中からコマンドを探すので、今いるフォルダのファイルは見に行きません。

% hello.py
zsh: command not found: hello.py
% echo $?
127

Python が起動したあとで出る PermissionError: [Errno 13] は、スクリプトが開こうとしたファイルの権限の問題で、こちらとは別物です。そちらはPermissionError: [Errno 13] の記事で扱っています。

chmod +x だけだと syntax error に変わる

permission denied を見て実行権限を付けると、今度はこうなりました。

% chmod u+x hello.py
% ./hello.py
./hello.py: line 1: syntax error near unexpected token `"hello"'
./hello.py: line 1: `print("hello")'

Python の文法エラーに見えますが、Python は起動していません。zsh のマニュアル(man zshmisc の COMMAND EXECUTION)に、実行形式でないファイルは「シェルスクリプトとみなして /bin/sh で実行する」と書かれていて、そのとおりの動きです。

$ MANPAGER=cat man zshmisc | col -b | grep -A3 "not in executable format"
       If execution fails because the file is not in executable format, and
       the file is not a directory, it is assumed to be a shell script.
       /bin/sh is spawned to execute it.  If the program is a file beginning
       with `#!', the remainder of the first line specifies an interpreter for

このMacの /bin/sh の中身は bash でした。zsh で打ったのに line 1: syntax error near unexpected token という bash の書式で出るのはこのためです。

$ ls -l /private/var/select/sh
lrwxr-xr-x  1 root  wheel  9  8月 13 11:51 /private/var/select/sh -> /bin/bash

1行目が import sys のファイルだと、出方がまた変わります。import というコマンドを探して見つからず、2行目で文法エラーになります。

$ printf "import sys\nprint(sys.executable)\n" > where.py; chmod +x where.py; ./where.py; echo "rc=$?"
./where.py: line 1: import: command not found
./where.py: line 2: syntax error near unexpected token `sys.executable'
./where.py: line 2: `print(sys.executable)'
rc=2

line 1: や command not found が Python のトレースバック(Traceback (most recent call last):)の形をしていなければ、シェルがファイルを読んでいる、と見分けられます。

1行目に shebang を書くと ./ で動く

1行目に #!/usr/bin/env python3 を足すと、同じ起動方法で Python が使われます。どの Python が使われたかを表示させました。

% cat where.py
#!/usr/bin/env python3
import sys
print(sys.executable)
% ./where.py
~/opt/anaconda3/bin/python3
% source venv/bin/activate
((venv) ) % ./where.py
/private/tmp/itmemo99.GcOUVJ/venv/bin/python3
((venv) ) % deactivate

#!/usr/bin/env python3 は「PATH で最初に見つかる python3 で動かす」という意味です。このMacでは Anaconda が PATH の先頭にいるので、何もしなければ Anaconda の 3.9.7 で動きました。仮想環境を有効化すると、その中の Python に切り替わります。python3 hello.py で動かす場合も、使われるのは同じく PATH で最初の python3 です。((venv) ) という表示は、このMacの Homebrew 3.12 で作った venv の表示のくせで、動作には関係ありません(詳しくはvenv が有効化できないときの記事に書きました)。

shebang の書き方は Python 公式チュートリアルの付録「実行可能な Python スクリプト」にあります(付録(Python 公式ドキュメント))。#! はファイルの最初の2文字でなければならず、改行は Unix 形式である必要がある場合がある、とも書かれています。次の2つはその実例です。

#!/usr/bin/python と書いた場合

% ./old.py
zsh: ./old.py: bad interpreter: /usr/bin/python: no such file or directory
% echo $?
127

bad interpreter: の後ろが、1行目に書かれた Python の場所です。このMac(macOS 26.6.2)には /usr/bin/python が無く、/usr/bin/python3 だけがありました。古い記事のスクリプトをそのまま使うと出る形です。

Windows で作ったファイル(改行が CRLF)の場合

% ./crlf.py
env: python3\r: No such file or directory
% echo $?
127
% perl -pi -e 's/\r$//' crlf.py
% ./crlf.py
1

env: python3\r の \r は、行末の改行コード CR が名前にくっついて読まれているという意味です。env は「python3 と CR」という名前のコマンドを探して見つけられていません。行末の CR を取り除くと動きました。エディタの改行コード設定を LF にしても同じです。

ディレクトリを ./ で実行しても同じ表示になる

打ち間違えてフォルダ名を実行した場合も、zsh では同じ文言でした。bash では is a directory と出るので分かりやすいのですが、zsh では区別がつきません。

% ls -ld tools
drwxr-xr-x  2 me  wheel  64 10月 19 00:09 tools
% ./tools
zsh: permission denied: ./tools
$ ./tools; echo "rc=$?"   # bash で実行
bash: ./tools: is a directory
rc=126

ls -ld の1文字目が d ならディレクトリです。

フォルダ側に x が無いと python3 でも動かない

ファイルではなく、それを入れているフォルダの x(中に入る権限)が無い場合も試しました。この場合は python3 に渡しても Python 側で同じ理由で失敗します。

% ls -ld locked
drw-r-xr-x  3 me  wheel  96 10月 19 00:09 locked
% ./locked/run.py
zsh: permission denied: ./locked/run.py
% python3 locked/run.py
python3: can't open file '/private/tmp/itmemo99.GcOUVJ/locked/run.py': [Errno 13] Permission denied
% chmod u+x locked
% ./locked/run.py
ok

drw-r-xr-x の持ち主の欄が rw- で x がありません。フォルダの x は「中のファイルにたどり着く」ための権限なので、中の run.py に実行権限があっても届きません。最後の2行のとおり、chmod u+x locked でフォルダに x を戻すと動きました。python3 側のメッセージは can't open file の後ろに絶対パス、最後に [Errno 13] が付く形で、こちらは Python が出しています。python3 ファイル名 でも permission denied が出るときは、途中のフォルダを ls -ld で1つずつ見ます。

避けたほうがいい対処

  • sudo ./hello.py:原因は「起動のしかた」なので、管理者権限は関係ありません。
  • chmod 777 hello.py:自分以外のユーザーにも書き込みを許してしまいます。足りないのは持ち主の x だけなので chmod u+x で足ります。

Apple のサポートページでも、ファイルを実行可能にする方法として chmod が案内されています(Macの「ターミナル」でファイルを実行可能ファイルにする(Apple サポート))。ただしそこで扱っているのはシェルスクリプトで、Python スクリプトの場合は上のとおり shebang も要ります。

検証した環境

この記事の調査・再現・執筆は、運営者の指示のもとでAIエージェント(AnthropicのClaude)が行い、公開するかどうかは運営者が決めています。載せた出力は、そのAIエージェントがこのMacで実際にコマンドを実行して得たものです。

  • macOS 26.6.2(Apple シリコン)
  • zsh 5.9(ログインシェル)、比較に bash 3.2.57(macOS 付属、/bin/sh の中身もこれ)
  • ~/opt/anaconda3/bin/python3:Python 3.9.7(PATH の先頭)
  • /usr/bin/python3:Python 3.9.6(Xcode Command Line Tools)。/usr/bin/python は無し
  • 仮想環境は /opt/homebrew/bin/python3.12(Python 3.12.13)で作成
  • 実施日:2026年10月19日。/tmp の下の一時フォルダで実行

コメントを残す

メールアドレスが公開されることはありません。 ※ が付いている欄は必須項目です

トップへ戻る