shell_exec不能直接执行含换行符的多行命令字符串,因换行被当作普通字符而非语句分隔符;必须用分号、&&或括号等shell语法显式分隔命令,且需对用户输入严格转义防注入。

shell_exec 不能直接执行多行命令字符串
你写 shell_exec("ls -l\npwd"),它不会按两行分别执行,而是把换行符当普通字符传给 shell —— 大多数情况下等价于 ls -l pwd(即把 pwd 当作 ls 的参数),结果报错或输出异常。
真正能“执行多行”的,是让 shell 自己解析换行。必须用分号 ;、逻辑运算符 && 或换行转义方式,让 shell 把它们识别为多个语句。
- 用分号连接:
shell_exec("ls -l /tmp; pwd; date") - 用
&&保证前一条成功才执行下一条:shell_exec("mkdir /tmp/test && echo 'ok' > /tmp/test/log") - 用括号包裹多条命令(适合需要变量或流程控制):
shell_exec("(cd /tmp && ls -t | head -3)")
为什么加了 \n 还是只执行第一行?
因为 shell_exec() 底层调用的是系统 shell(如 bash),而 shell 对换行的处理取决于上下文:在交互式终端里敲回车会触发执行,但在 shell_exec() 的单字符串参数中,换行只是字符串内容,不自动触发新命令解析。
常见错误现象:
立即学习“PHP免费学习笔记(深入)”;
-
shell_exec("echo hello\nls -l")→ 输出hello\nls -l(字面量),或报ls: cannot access 'l': No such file - 用 PHP 的 heredoc 或 nowdoc 写多行字符串,不加连接符,效果一样无效
解决办法只有一个:显式用 shell 语法分隔命令,而不是依赖 PHP 字符串换行。
PHP7.4 下要注意的兼容性细节
PHP7.4 默认禁用部分危险函数,shell_exec() 可能被 disable_functions 列表禁用。执行前先确认:
- 检查
ini_get('disable_functions')是否包含shell_exec - Windows 下注意:底层管道以文本模式打开,二进制输出可能损坏;Linux/macOS 无此问题
-
shell_exec()在失败或无输出时返回null,不是空字符串,判空要用=== null,别用empty() - 错误输出(stderr)默认不被捕获,要合并就得加
2>&1,例如:shell_exec("gunzip -t file.gz 2>&1")
带用户输入时怎么安全拼接多条命令
绝对不要这样写:"ls -l " . $_GET['dir'] . "; rm -rf " . $_GET['target'] —— 这等于主动邀请命令注入。
正确做法是:每条命令独立构造,每个参数单独转义:
- 用
escapeshellarg()包裹每个外部输入值:shell_exec("ls -l " . escapeshellarg($_GET['dir']) . " 2>&1") - 多条命令之间仍用
;或&&连接,但每段都确保参数已转义 - 更稳妥的方式是拆成多次
shell_exec()调用,避免逻辑耦合和错误传播 - 如果涉及路径、文件名等,优先用
realpath()和白名单校验,再拼命令
复杂逻辑别硬塞进一行 shell 命令里;该写脚本就写脚本,用 shell_exec('/path/to/safe-script.sh ' . escapeshellarg($arg)) 更可控。



















