在 Linux 下运行一个脚本或程序,并不是简单地在命令行中输入文件名。系统需要解决三个问题:这个文件要怎么执行(执行方式)、你有没有运行它的资格(权限),以及系统要去哪里找到它(执行路径)。日常使用时遇到的“command not found”或“Permission denied”错误,几乎都与此有关。
1. 执行方式:直接调用 vs. 解释器调用
执行一个可执行文件主要有两种途径。
直接执行:直接用文件路径运行,要求文件本身具有可执行权限,并且是一个二进制可执行程序(如编译好的 C 程序)或带有正确 shebang 的文本脚本。
./my_script.sh
/home/user/bin/my_program
对于脚本文件,内核会读取文件第一行的 shebang(如 #!/bin/bash 或 #!/usr/bin/env python3),然后调用指定的解释器来执行该脚本。如果脚本没有 shebang,直接执行时会报错,或者由当前 Shell 尝试解释。
解释器显式调用:直接将脚本文件名作为解释器的参数,此时脚本不需要可执行权限,也不需要 shebang。
bash my_script.sh
python3 script.py
这种方式明确告诉系统用哪个程序去解析这个文件,适用于临时测试或权限受限的场景。
2. 权限:可执行位的决定性作用
Linux 的文件权限中有一个 可执行位(x),它决定一个文件能否被当作程序直接运行。用 ls -l 查看文件时,可执行位显示为 x:
$ ls -l script.sh
-rw-r--r-- 1 user user 0 Mar 20 10:00 script.sh # 无可执行权限
-rwxr-xr-x 1 user user 0 Mar 20 10:00 script.sh # 有可执行权限
只有文件的可执行位对当前用户设置时,才能使用 ./script.sh 的方式直接运行。修改权限使用 chmod 命令:
chmod +x script.sh # 为所有用户添加可执行权限
chmod 755 script.sh # 数字方式:所有者可读写执行,同组和其他人可读可执行
即使脚本内容正确,如果权限位没有设置 x,直接运行也会得到 Permission denied 错误。这是 Linux 避免意外执行任意文件的一道安全机制。
对于目录,可执行位表示能否进入该目录(cd 进去)。没有目录的可执行权限,即使你能列出目录下的文件名,也无法访问里面的文件。
3. 执行路径:PATH 环境变量的查找顺序
当你输入一个命令(如 ls 或 python3)而不指定完整路径时,Shell 会按照 PATH 环境变量 中列出的目录顺序,去逐个查找同名的可执行文件,找到第一个就执行。
查看当前 PATH:
echo $PATH
# 典型输出:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin
目录之间用冒号分隔。你可以临时追加一个目录,让 Shell 也能在其中搜索:
export PATH="/home/user/scripts:$PATH"
如果将你自己的脚本目录放在 PATH 最前面,则会优先执行你的版本。
注意安全的常见做法:当前目录(.)通常 不在 PATH 中,这是一种安全设计。如果 PATH 包含当前目录,当你处在一个别人可控的目录(如 /tmp)并输入 ls 时,可能执行的是一个假冒的 ls 程序。因此要运行当前目录下的可执行文件,必须明确使用 ./ 前缀,如 ./my_script。
4. 常用命令与调试
which或command -v:显示某个命令在 PATH 中的实际路径。
which python3 # /usr/bin/python3
type:告诉你会如何解释一个命令(别名、函数、内建命令、外部程序)。
type ls # ls is aliased to `ls --color=auto'
type -a echo # echo is a shell builtin / echo is /usr/bin/echo
file:识别文件类型,可以判断一个文件是脚本还是二进制程序。
file /bin/ls # ELF 64-bit LSB executable ...
file script.sh # script.sh: Bourne-Again shell script, ASCII text executable
当你遇到“command not found”时,要依次检查:命令名是否拼错、程序是否已安装、所在目录是否在 PATH 中。若在 PATH 中仍然找不到,可能还需要用 hash -r 刷新 Shell 的命令缓存。
理解执行方式、权限和执行路径这三者之间的关系,能够让你快速定位脚本无法运行的根本原因,也让你可以更好地组织自己的 ~/bin 目录,打造一套高效的个人命令行工具箱。