在 PHP 開發中,有時需要直接呼叫系統層級的 Shell 指令,例如重啟 Nginx、執行備份腳本等。最常用的函式是 shell_exec(),它能將指令的完整輸出以字串形式返回。但新手常踩的一個坑是:若指令輸出到 stderr(標準錯誤輸出),而未重導向至 stdout,PHP 將捕獲不到任何內容,導致回傳值為空。
$message = shell_exec("sudo /usr/local/webserver/nginx/sbin/nginx -t 2>&1");
echo "執行結果:" . $message . "<br/>";
2>&1 的作用2>&1 將「檔案描述符 2(stderr)重導向至檔案描述符 1(stdout)」。這樣,無論指令是正常輸出還是報錯,所有訊息都會合併流向 stdout,進而被 shell_exec() 捕獲並回傳。
sudo 需要 Apache/Nginx 執行使用者(如 www-data)在 /etc/sudoers 中獲得免密權限,否則指令會靜默失敗。exec() 搭配 $output、$return_var 參數;若需即時串流輸出,請使用 proc_open()。escapeshellarg() 或 escapeshellcmd() 防止指令注入。<?php
// 測試有無 2>&1 的差異
$cmd = "ls /not_exist_dir";
echo "無重導向:" . shell_exec($cmd) . "<hr>";
echo "有重導向:" . shell_exec($cmd . " 2>&1") . "<hr>";
執行上述腳本,第一組通常顯示空白,第二組則會輸出 ls: cannot access '/not_exist_dir': No such file or directory,直觀驗證重導向的必要性。