208 个代码(共 208 个)
该操作需要进程所不具备的特权,例如更改文件的所有者、向其他用户的进程发送信号或修改不可变文件(chattr +i)。与 EACCES 不同,更改文件权限无法解决:需要 root 或相应的 capability。
文件或目录不存在。当路径中缺少某个中间目录、符号链接指向不存在的目标,或脚本 #! 行中的解释器没有安装时,也会出现此错误。
不存在具有该标识符的进程、进程组或线程;例如对已经结束的 PID 执行 kill。
系统调用在完成之前被信号中断。这不是真正的错误:程序应重试该调用,或使用 SA_RESTART 安装信号处理程序。
底层输入/输出错误,通常发生在读写设备时。对于磁盘,通常意味着有坏扇区或线缆故障:请检查 dmesg 和 SMART 状态。向已关闭的终端写入时也会出现。
设备或地址不存在:设备文件存在,但背后没有硬件;或者以 O_NONBLOCK 方式打开一个没有读取者的 FIFO 进行写入。
传给 exec 的参数和环境变量列表过大。这就是使用会展开成数千个文件的通配符时经典的“Argument list too long”;请改用 find -exec 或 xargs。
文件不是可识别的可执行格式:它是其他架构的二进制文件、已损坏,或是没有 #! 行的脚本。
文件描述符无效、已关闭,或其打开模式不允许该操作,例如向以只读方式打开的描述符写入。
该进程没有可用 wait 或 waitpid 等待的子进程,通常是因为 SIGCHLD 被忽略,子进程会被自动回收。
资源暂时不可用,应稍后重试。在非阻塞操作中,表示还没有数据或空间;在 fork 中,表示已达到进程或线程数上限(ulimit -u 或 cgroup 的 pids.max)。
相同值:EWOULDBLOCK
内存不足以完成该操作,或超出了进程的某项内存限制。在 fork 或 mmap 中,可能是 overcommit 策略、cgroup 限制或地址空间不足导致的。
权限被拒绝,原因可能是文件或路径中某个目录的权限(每个目录都需要执行权限)、ACL、SELinux 或 AppArmor,或者以 noexec 方式挂载。没有特权时使用小于 1024 的端口,bind 也会返回此错误。
传给系统调用的指针指向无效的内存地址。这说明程序存在 bug。
该操作需要块设备(如磁盘),收到的却是其他类型的文件;例如不加 -o loop 挂载普通文件。
设备或资源正忙。常见于卸载仍有打开的文件或有终端位于其中的文件系统;lsof 或 fuser 可以显示哪些进程在使用它。
已存在同名的文件、目录或其他对象,例如使用 O_EXCL 创建、不带 -p 使用 mkdir,或创建链接时目标已存在。
不能在不同的文件系统之间创建硬链接或重命名文件。mv 通过先复制再删除来解决;使用 rename() 的程序也必须这样做。
设备不存在或不支持该操作;例如挂载某种文件系统类型时,其内核模块没有加载。
路径中本应是目录的某个部分是一个文件,或者请求的是目录(O_DIRECTORY),但对象并不是目录。
对目录执行了文件操作,例如以写入方式打开它。
某个参数对该调用无效:值超出范围、选项组合不兼容,或对象不支持该操作。这是一个通用错误:该调用的 man 手册页列出了具体情况。
整个系统的打开文件表已耗尽。可以通过 sysctl 中的 fs.file-max 调整该限制。
进程已达到打开描述符数量的上限(“Too many open files”)。可以用 ulimit -n 或 systemd 中的 LimitNOFILE 提高限制,并检查程序是否有未关闭的文件或套接字。
对非终端的对象请求了终端操作(ioctl),例如交互式程序的输出被重定向到文件或管道时。
可执行文件正在使用中:不能写入正在运行的二进制文件,也不能执行仍以写入方式打开的文件。要更新它,最好写入一个新文件再重命名。
文件超出了文件系统支持的最大大小(FAT32 为 4 GB)或进程的 RLIMIT_FSIZE 限制。
设备上没有剩余空间。如果 df 显示还有可用空间,请用 df -i 检查 inode。inotify 在 fs.inotify.max_user_watches 耗尽时也会返回此错误。
不能对管道、FIFO 或套接字执行 lseek,因为它们没有位置。
文件系统以只读方式挂载。如果在没人要求的情况下变成了只读,那是内核检测到了错误:请检查 dmesg 并运行 fsck。
超出了一个文件的硬链接最大数量;在某些文件系统中,则是一个目录的子目录最大数量。
向另一端已关闭的管道或套接字写入(“Broken pipe”)。除了这个错误,进程还会收到 SIGPIPE;当读取端提前结束时这是正常的,例如 cmd | head。
数学函数的参数超出了其定义域,例如负数的平方根。
函数的结果太大或太小而无法表示,或缓冲区不足以容纳结果,例如以过短的缓冲区调用 getcwd。
避免了一次死锁:所请求的锁(如 fcntl 文件锁或带错误检查的互斥锁)将会永远等待下去。
相同值:EDEADLOCK
路径或其中某一部分超过了最大长度:在 Linux 中,通常每个名称为 255 字节,整个路径为 4096 字节。
没有可用的锁。在 NFS 中,通常表示锁服务(lockd 或 rpc.statd)没有运行。
该系统调用在此内核中不存在或未实现。常见于为较新内核编译的二进制文件,或不认识新系统调用的容器 seccomp 配置文件。
目录非空,例如使用 rmdir 或重命名覆盖已有目录时。要连同内容一起删除,请使用 rm -r。
解析路径时遇到过多串联的符号链接,通常是因为存在循环;或者对符号链接使用了 O_NOFOLLOW。
System V 消息队列中没有所请求类型的消息。
System V IPC 标识符(消息队列、信号量或共享内存)在进程使用期间被删除。
通道号超出范围。这是一个遗留代码,在 Linux 中没有实际用途。
第 2 级不同步。这是 System V 的遗留代码,在 Linux 中没有实际用途。
第 3 级已停止。这是 System V 的遗留代码,在 Linux 中没有实际用途。
第 3 级已重置。这是 System V 的遗留代码,在 Linux 中没有实际用途。
链接号超出范围。这是一个遗留代码,在 Linux 中没有实际用途。
协议驱动程序未连接。只有少数子系统使用它,例如某些蓝牙驱动程序。
没有可用的 CSI 结构。这是一个遗留代码,在 Linux 中没有实际用途。
第 2 级已停止。这是 System V 的遗留代码,在 Linux 中没有实际用途。
无效的交换。这是一个遗留代码,某些驱动程序和文件系统会赋予它自己的含义加以重用。
无效的请求描述符。这是一个遗留代码,某些驱动程序会赋予它自己的含义加以重用。
交换已满。这是一个遗留代码,在 Linux 中没有实际用途。
没有“anode”。这是一个遗留代码,在 Linux 中没有实际用途。
无效的请求代码。这是遗留代码;某些驱动程序用它表示不支持的命令。
无效的槽(slot)。这是一个遗留代码,在 Linux 中没有实际用途。
字体文件格式错误。这是一个遗留代码,在 Linux 中没有实际用途。
设备不是 STREAM。它属于 System V 的 STREAMS 接口,Linux 没有实现该接口。
没有可用数据。在 Linux 中,扩展属性不存在时 getxattr 会返回它;在 macOS 中,这种情况对应的是 ENOATTR。
定时器超时。它源自 STREAMS;在 Linux 中,某些驱动程序和 io_uring 将它用于有时间限制的操作。
STREAMS 资源已耗尽,而 Linux 并没有实现该接口。
计算机不在网络上。这是一个很少使用的遗留代码。
软件包未安装。这是遗留代码;某些子系统在缺少模块(例如加密模块)时会使用它。
对象是远程的。在 NFS 中,表示该路径是从另一台服务器导出的。
链接已断开。这是遗留代码;某些驱动程序在与设备失去连接时会使用它。
“advertise”错误。这是 RFS 的遗留代码,在 Linux 中未使用。
“srmount”错误。这是 RFS 的遗留代码,在 Linux 中未使用。
发送时出现通信错误。这是遗留代码;某些网络和 USB 驱动程序会使用它。
协议错误:对端或设备返回了意外的响应。会出现在 USB 设备上,以及在交换过程中断开的连接中。
尝试了多跳(multihop)。这是 RFS 的遗留代码。
RFS 特有的错误。在 Linux 中未使用。
消息格式错误或已损坏。元数据校验和验证失败时,ext4、XFS 和 Btrfs 会返回它,别名为 EFSBADCRC。
相同值:EFSBADCRC
值无法放入目标数据类型;例如,编译时未启用大文件支持的 32 位程序打开超过 2 GB 的文件。
名称在网络上不唯一。这是一个遗留代码。
文件描述符处于错误的状态。ALSA 和某些驱动程序在设备未就绪时会使用它。
远程地址已更改。这是一个遗留代码。
无法访问所需的共享库。这是 a.out 二进制文件的遗留代码。
共享库已损坏。这是 a.out 二进制文件的遗留代码。
a.out 二进制文件的 .lib 节已损坏。这是一个遗留代码。
尝试链接的共享库过多。这是 a.out 的遗留代码。
共享库不能直接执行。这是 a.out 的遗留代码。
字节序列对该字符编码无效,例如使用 iconv 或多字节函数转换不是有效 UTF-8 的文本时。
被中断的调用应当重新启动。它仅供内核内部使用,不应传到程序中。
STREAMS 管道错误。音频设备处于挂起状态时,ALSA 会返回它。
用户过多。磁盘配额系统在其表已满时会返回它,这种情况很少见。
对不是套接字的描述符执行了套接字操作。
缺少目标地址:通过无连接套接字发送时没有指定发往何处。
消息对该套接字来说太大,例如 UDP 数据报超过了最大值,或在不允许分片时超过了 MTU。
协议与套接字类型不匹配。
所请求的套接字选项或协议不可用,例如内核不认识的 setsockopt 选项。
不支持该协议,例如因为其内核模块没有加载。
该地址族不支持此套接字类型。
套接字或对象不支持该操作。在 Linux 中它与 ENOTSUP 的值相同,许多文件系统对未实现的功能(如 fallocate 或扩展属性)会返回它。
不支持该操作。在 Linux 中它与 EOPNOTSUPP 的值相同(95);在 macOS 中则是不同的代码。
不支持该协议族。
不支持该地址族;常见于在禁用了 IPv6 的系统或容器中使用 IPv6。
地址和端口已被占用:另一个进程正在监听该端口,或之前的连接仍处于 TIME_WAIT 状态。可用 ss -ltnp 或 lsof -i :端口 找到该进程,或使用 SO_REUSEADDR。
无法分配所请求的地址:该 IP 不属于本机的任何接口,或者用于出站连接的临时端口已耗尽。
网络接口已关闭。
目标网络不可达,因为没有通往它的路由。请检查路由表和网关;在没有 IPv6 连通性时通过 IPv6 连接也会出现此错误。
网络重置了连接,例如 keepalive 失败时。
连接在本地被中止,例如客户端在服务器用 accept 接受连接之前就关闭了它。
对端用 RST 突然断开了连接(“Connection reset by peer”):远程进程已关闭、防火墙或负载均衡器切断了空闲连接,或者发送了对端未预期的数据。
内核中没有可用于该网络操作的缓冲区空间;通常出现在流量很大或套接字队列已满时。
套接字已连接。
套接字未连接:在连接之前尝试发送或接收,或者连接已经关闭。在 FUSE 挂载中,当其进程已退出时会显示为“Transport endpoint is not connected”;用 fusermount -u 卸载即可解决。
用 shutdown 关闭套接字的该方向后,无法再发送。
引用过多;在 Linux 中,是通过 Unix 套接字传递了过多嵌套的描述符。
连接超时,因为目标没有响应。通常是由于防火墙静默丢弃了数据包、主机已关机或路由不通。
目标拒绝了连接:主机有响应,但该端口上没有程序在监听,或防火墙回复了拒绝。请确认服务正在运行,并且在正确的接口上监听,而不仅仅是 127.0.0.1。
目标主机已宕机。
没有到主机的路由:它在本地网络中不响应 ARP,或者路由器或防火墙报告它不可达。
套接字上已有操作正在进行,例如尚未完成的非阻塞 connect。
操作正在进行:非阻塞 connect 已经开始,稍后才会完成。这不是错误;需要用 poll 或 select 等待。
文件句柄已失效:在 NFS 中,该文件或目录已在服务器上被删除或替换。重新打开路径或重新挂载即可解决。
结构需要清理:文件系统检测到了损坏(在 ext4 和 XFS 中,别名为 EFSCORRUPTED)。请卸载它并运行 fsck 或 xfs_repair。
相同值:EFSCORRUPTED
不是 XENIX 命名类型文件。这是一个已不再使用的遗留代码。
没有可用的 XENIX 信号量。这是一个已不再使用的遗留代码。
是 XENIX 命名类型文件。这是一个已不再使用的遗留代码。
远程 I/O 错误,例如 I2C 设备或远程磁盘没有响应。
超出了用户或组的磁盘配额。
设备中没有介质,例如光驱中没有光盘或读卡器中没有卡。
介质类型不正确。
操作已取消,例如异步 I/O 或 io_uring 的等待。
所需的密钥不在内核密钥环(keyring)中。出现在加密文件系统(如 fscrypt 或 eCryptfs)中密钥未加载时。
密钥已过期。PAM 和 Kerberos 在密码或票据过期时也会使用它。
密钥已被吊销。
服务拒绝了该密钥。
健壮互斥锁的持有者在未释放它的情况下终止了。新的持有者必须使受保护的状态恢复一致,并调用 pthread_mutex_consistent。
由健壮互斥锁保护的状态无法恢复,因为之前的持有者已终止,且没有人将其标记为一致。
无法执行该操作,因为 Wi-Fi 或蓝牙无线电被 RF-kill 阻止。请检查 rfkill list、物理开关或飞行模式键。
该内存页存在硬件错误,内核已将其标记为中毒(poisoned)。
文件类型不适合该操作。它在 macOS 和 BSD 中早已存在;在 Linux 中是最近才加入的。
进程过多。BSD 将其定义用于进程数限制,但实际上 fork 返回的是 EAGAIN。
RPC 结构错误(Sun RPC,NFS 使用它)。
RPC 版本不匹配(Sun RPC,NFS 使用它)。
服务器上的 RPC 程序不可用。
RPC 程序版本不匹配。
RPC 程序中不存在该过程。
身份验证错误,例如挂载 NFS 资源时。
该操作需要身份验证器。
设备电源已关闭。
设备错误,例如打印机缺纸。
可执行文件无效。
可执行文件适用于其他类型的 CPU,例如在未安装 Rosetta 2 的 Apple Silicon Mac 上运行仅支持 x86_64 的二进制文件,或在 Intel Mac 上运行 ARM 二进制文件。
共享库版本不匹配。
Mach-O 文件格式错误或已损坏。
扩展属性不存在;相当于 Linux 中的 ENODATA。使用 xattr 时会出现,例如从没有 com.apple.quarantine 属性的文件上删除该属性。
MAC Framework 中没有以该名称注册的策略。
网络接口的输出队列已满。
能力不足:受沙盒限制的调用会返回它。
控制该进程的终端已关闭,或 SSH 会话已断开。许多守护进程(如 nginx、sshd 或 rsyslog)将其视为重新读取配置的请求;nohup、tmux 和 screen 可防止它在退出时关闭进程。
通过键盘按 Ctrl+C 发出的中断。程序可以捕获它以便有序地结束。退出码 130。
通过键盘按 Ctrl+\ 发出的退出。它会终止进程并生成核心转储;而 JVM 则用它来打印线程状态。
处理器遇到了非法指令:为较新 CPU 编译的二进制文件(例如在不支持 AVX2 或 AVX-512 的处理器上使用了这些指令)、损坏的代码,或跳转到了数据区。
调试陷阱:调试器用它来实现断点。如果在没有调试器时收到,通常是程序自身检测到的故障,例如 macOS 上 Swift 的检查。
进程调用了 abort():断言失败、未捕获的 C++ 异常,或 C 库检测到堆损坏(“double free or corruption”)。退出码 134。
相同值:SIGIOT
总线错误:在某些架构上访问未对齐的内存,或者访问用 mmap 映射的文件中因文件被截断而已不存在的部分。/dev/shm 写满时也会发生。
算术异常。尽管名称如此,最常见的原因是整数除以零。
立即终止进程:无法捕获、阻塞或忽略。发送它的有 kill -9、内存耗尽时内核的 OOM killer,以及容器超出内存限制(OOMKilled)或在 SIGTERM 之后未及时结束时的 Docker 或 Kubernetes。退出码 137。
留给各应用程序自行定义用途的信号;例如 dd 会报告其进度,nginx 会重新打开日志。
段错误(“Segmentation fault”):访问了无效内存,例如解引用空指针、数组越界,或因无限递归导致栈溢出。退出码 139。
第二个留给各应用程序自行定义用途的信号。
向没有读取者的管道或套接字写入。在 cmd | head 中这是正常的,因为读取端会先结束;服务器通常会忽略它并处理 EPIPE 错误。退出码 141。
用 alarm 或 setitimer 设置的定时器已到期。
请求有序终止。它是 kill、systemctl stop、docker stop 以及 Kubernetes 删除 Pod 时的默认信号;进程应关闭其连接并退出。退出码 143。
协处理器栈错误。当前的 Linux 已不再使用。
子进程已终止、暂停或继续运行。父进程必须用 wait 回收它;否则子进程会变成僵尸进程。
相同值:SIGCLD
恢复已暂停的进程,就像 shell 中的 fg 和 bg 所做的那样。
暂停进程;无法捕获或忽略。用 SIGCONT 恢复。
在终端中按 Ctrl+Z 发出的暂停。与 SIGSTOP 不同,程序可以捕获它。
后台进程尝试从终端读取。
后台进程在启用 stty tostop 时尝试向终端写入,或尝试更改终端的配置。
套接字收到了紧急(带外)数据。Go 在内部用它来中断 goroutine。
超出了进程的 CPU 时间限制(ulimit -t)。
超出了进程允许的最大文件大小(ulimit -f)。
虚拟定时器已到期,该定时器只计算进程的 CPU 时间。
性能分析定时器已到期,供性能分析工具(profiler)使用。
终端窗口的大小已改变;全屏程序用它来重绘界面。
设置了 O_ASYNC 的描述符上有可用的 I/O。在 Linux 中,SIGPOLL 是同一个信号。
相同值:SIGPOLL
电源故障,由 UPS 软件通知 init 系统。
错误的系统调用。如今常见的原因是 seccomp 过滤器阻止了该调用,例如在容器中。
仿真陷阱(EMT)。它存在于 macOS 和 BSD 中,但在 x86 或 ARM 上的 Linux 中不存在。
在 macOS 和 BSD 的终端中按 Ctrl+T 发出的信息请求;许多命令会以显示进度作为响应。
命令成功完成。这是唯一表示成功的代码:其他任何值都表示错误。
一般错误;其含义由各程序自行决定。详细信息通常在命令写入 stderr 的内容中。grep 和 diff 赋予它另一种含义:“未找到匹配项”或“文件不同”。
shell 内置命令使用不当或脚本存在语法错误。许多程序也用它表示无效的选项,而 grep 用它表示真正的错误。
命令使用不当:缺少参数、参数多余或某个选项不正确。
输入数据的格式不正确。
某个输入文件不存在或无法读取。
指定的用户不存在;主要由邮件程序使用。
主机名不存在。
所需的服务不可用,或发生了无法归入其他类别的故障。
程序内部错误。
操作系统错误,例如无法 fork 或创建管道。
缺少某个系统文件(如 /etc/passwd),或该文件有错误。
无法创建输出文件。
读写文件时发生输入/输出错误。
临时故障:建议稍后重试。邮件服务器用它将邮件留在队列中。
远程系统的响应不符合协议。
权限不足,无法执行该操作。
配置有错误。
命令因超出指定的时间而被 timeout 命令终止。
docker run 本身在运行容器之前就失败了,例如选项错误或守护进程出错。GNU timeout 在自身失败时也会返回此值。
文件存在,但无法执行:缺少执行权限、是一个目录,或是其他架构的二进制文件。在 Docker 中,表示容器的命令不可执行。
未找到命令:没有安装、不在 PATH 中或名称拼写错误。在脚本中,缺少 #! 行的解释器时也会出现;在 Docker 中,表示容器的命令在镜像中不存在。
大于 128 的代码表示进程被信号终止,但 128 不对应任何信号。Git 将它用于所有致命错误(“fatal: …”),例如仓库不存在或克隆时身份验证失败。
退出码超出了范围:exit -1 会变成 255,因为只保留 8 位。ssh 在连接或身份验证失败时也会返回它,以便与远程命令的退出码区分开。
Linux 的值是 x86、x86-64 和 ARM 上的值;Alpha、MIPS、SPARC 和 PA-RISC 对部分 errno 和信号的编号不同。英文消息是 glibc 中 strerror 和 strsignal 显示的内容,macOS 的消息不同时也会一并列出。大于 128 的退出码按 128 加信号编号解读,这是 bash、Docker 和 Kubernetes 的约定。
工作原理
在 Linux 中,系统调用失败时会返回 -1,并在变量 errno 中留下一个说明原因的数字:2 是 ENOENT,文件不存在;13 是 EACCES,权限被拒绝。strerror 会把这个数字转换成屏幕上看到的文本,例如“No such file or directory”。Python 将其显示为 [Errno 13],Node.js 显示为 code: 'ECONNREFUSED',Go、Rust 或 Java 则显示同样的文本。1 到 34 的编号来自最初的 Unix,在所有系统中都相同;之后的编号由各系统自行分配,因此 ECONNREFUSED 在 Linux 中是 111,在 macOS 中是 61。名称是可移植的,数字则不是。
信号是内核或其他进程发给某个进程的通知:按下 Ctrl+C 时发送 SIGINT,SIGTERM 请求它结束,SIGKILL 不经询问直接终止它,访问无效内存时则会收到 SIGSEGV。每个信号都有默认动作,而且几乎都可以被捕获以执行其他操作。当信号杀死进程时,shell 会将退出码报告为 128 加信号编号:137 是 SIGKILL(9),139 是 SIGSEGV(11),143 是 SIGTERM(15)。Docker 和 Kubernetes 也使用相同的约定。
退出码是程序结束时留下的数字:0 表示成功,其他任何值都表示错误。只保留 8 位,因此范围是 0 到 255。约定很少:126 和 127 由 shell 在无法执行或找不到命令时使用,64 到 78 由 BSD 的 sysexits.h 定义,其余由各程序自行决定,例如 grep 在未找到任何内容时返回 1。
示例
Last State: Terminated · Reason: OOMKilled · Exit Code: 137137 = 128 + 9 · SIGKILL容器超出了内存限制,内核用 SIGKILL 杀死了它。需要提高 resources.limits.memory 中的限制,或查明进程为何消耗这么多内存;重启并不能解决问题。Error: connect ECONNREFUSED 127.0.0.1:5432ECONNREFUSED · Linux 111 · macOS 61 · Connection refusedNode.js 无法连接到 PostgreSQL,因为 5432 端口上没有程序在监听。如果应用运行在容器中,127.0.0.1 指的是容器本身而不是主机:应使用数据库服务的名称。OSError: [Errno 48] Address already in useEADDRINUSE · Linux 98 · macOS 4848 表明程序运行在 macOS 上:在 Linux 中同一个错误是 98。两种情况都是另一个进程已占用该端口;lsof -i :端口 可以显示是哪个进程。使用场景
- 理解 Python、Node.js、Go 或 C 应用程序中只显示 errno 编号或名称的错误。
- 根据退出码查明 Docker 容器为何退出或 Kubernetes Pod 为何重启。
- 将 macOS 的 errno 编号转换为正确的名称,因为从 35 开始它与 Linux 的不一致。
- 解读失败的脚本、cron 任务或 CI 作业的退出码。
- 选择用 kill 发送哪个信号,并了解进程不捕获它时会发生什么。
- 编写可移植的错误处理代码,按名称而不是按数字进行比较。
常见问题
exit code 137(退出码 137)是什么意思?
表示进程被信号 9,即 SIGKILL 终止(128 + 9)。最常见的原因是内存:容器超出了内存限制,Kubernetes 会将其报告为 OOMKilled;或者内核的 OOM killer 选中了该进程,dmesg 中会留下“Out of memory: Killed process”。使用 docker kill,或进程在收到 SIGTERM 后未在期限内结束时也会出现:docker stop 为 10 秒,Kubernetes 为 30 秒。
SIGTERM 和 SIGKILL 有什么区别?
SIGTERM 请求进程结束,进程可以捕获它,以便关闭连接、保存数据后再退出。SIGKILL 则由内核立即终止进程,进程对此无能为力。正确的做法是先发送 SIGTERM,等待几秒钟,只有在进程仍在运行时才使用 SIGKILL,systemd、docker stop 和 Kubernetes 正是这样做的。
为什么同一个 errno 在 macOS 中的编号不同?
因为 POSIX 只定义了名称,没有定义编号。1 到 34 的编号所有系统都继承自最初的 Unix;之后,BSD(macOS 源自它)和 System V(Linux 沿用了它)分别进行了编号。因此最好始终按名称比较:在 Python 中用 errno.ECONNREFUSED,在 Node.js 中用 err.code,在 C 中用常量,而不是用数字。
EACCES 和 EPERM 有什么区别?
EACCES(“Permission denied”)表示文件或路径中某个目录的权限不允许,或者被 ACL 或 SELinux 阻止:可通过 chmod、chown 或相应的策略解决。EPERM(“Operation not permitted”)表示操作本身需要特权,与权限无关,例如更改文件的所有者或杀死其他用户的进程:需要 root、某项 capability,或者移除不可变之类的属性。
如何查看命令或容器的退出码?
在 bash 和 zsh 中,echo $? 会显示上一条命令的退出码;在 PowerShell 中则用 $LASTEXITCODE。在 Docker 中,docker ps -a 会在 STATUS 列中显示它,例如“Exited (137)”。在 Kubernetes 中,kubectl describe pod 会在“Last State: Terminated”中显示它及原因,例如 OOMKilled 或 Error。