找回密碼
 立即註冊
    查看: 181|回覆: 0

    shell_command 與 command_line 完整指南:讓 Home Assistant 執行系統指令(含除錯與逾時處理)

    [複製鏈接]

    !lvup!   100%

    386

    主題

    27

    回帖

    2200萬

    積分

    管理員

    積分
    22006063
    發表於 2026-9-21 08:38:17 | 顯示全部樓層 |閱讀模式
    Home Assistant 裡總有那麼幾件事,內建整合做不到,但在終端機打一行指令就解決了。把那一行接進 Home Assistant 有兩個內建工具:shell_command 和 command_line。

    這兩個是 Home Assistant 裡最不好除錯的功能。失敗的時候通常什麼訊息都沒有,只有一個 unknown 的實體或一個什麼都沒發生的按鈕。這篇會一路做到「看得見錯誤訊息」為止。

    Home Assistant 裡總有那麼幾件事,內建整合做不到,但在終端機打一行指令就解決了。把那一行接進 Home Assistant 有

    這篇會做完的事


    • 先確認你要做的事是不是根本不需要這兩個(很多人在這裡就可以收工了)
    • 搞懂一件會改變一切的事:指令裡有沒有範本,決定它用哪一種方式執行
    • 做出三個 command_line 感測器、一個開關,每一個都有驗證步驟
    • 學會兩種除錯方法,其中一種可以直接看到指令的 stdout、stderr 和離開碼
    • 處理 60 秒硬性逾時 —— 這是最多人卡住卻沒人告訴他的地方
    • 用 ssh 從 Home Assistant 控制另一台機器,含金鑰怎麼產生、known_hosts 怎麼建


    全部做完約兩小時。需要一台 Home Assistant(這篇以 HAOS 為主)和一台想被控制的機器(NAS、路由器、電腦都行,沒有也可以跳過 ssh 那幾步)。

    第零步:先確認你不需要這兩個

    shell_command 是最後手段,不是第一選擇。 它沒有錯誤處理、沒有重試、依賴容器裡剛好有那支程式,而且升級之後可能默默失效。

    動手之前先對一次這張表:
    1. 你想做的事                     先用這個(內建、不必寫指令)
    2. -----------------------------  ----------------------------------------
    3. 喚醒一台電腦(Wake on LAN)     內建「Wake on LAN」整合,
    4.                                動作叫 wake_on_lan.send_magic_packet
    5. 打一個 HTTP API                 內建 rest_command:
    6. 讀一個 HTTP API 做成感測器      內建 rest: 平台
    7. ping 看某台機器在不在           內建「Ping」整合(已改成介面設定,沒有 YAML)
    8. 看 Home Assistant 主機的
    9. CPU、記憶體、磁碟               內建「System Monitor」整合
    10. 關機/重開 Home Assistant       內建 homeassistant.restart 等動作
    11. 定期把設定備份出去              內建備份系統(設定 → 系統 → 備份),
    12.                                2025.1 整套重做過,支援 Google Drive/OneDrive
    13. 真的需要外部指令的              為什麼
    14. -----------------------------  ----------------------------------------
    15. 去另一台機器上跑東西            ssh
    16. 讀主機上某個特定檔案的內容      cat /sys/... 這種沒有整合包裝的東西
    17. 呼叫某個只有命令列介面的工具    例如某些廠商自己的 CLI
    18. 把一堆東西串成一行             雖然串接有限制,見第二步
    複製代碼

    舉一個最常見的例子:舊教學一律教你用 shell_command: "wakeonlan AA:BB:CC舉一個最常見的例子D:EE:FF" 來喚醒電腦。今天的正確做法是內建整合:

    設定 → 裝置與服務 → 新增整合,搜尋 Wake on LAN,填入 MAC 位址。之後在自動化裡這樣用:
    1. actions:
    2.   - action: wake_on_lan.send_magic_packet
    3.     data:
    4.       mac: "AA:BB:CC:DD:EE:FF"
    複製代碼

    你會看到:這個動作不需要容器裡有任何外部程式,也不會有 60 秒逾時的問題。

    看完表還是需要外部指令的話,往下走。

    第一步:搞懂兩者的差別


    • shell_command —— 執行一個動作。它變成一個「動作(action)」,你在自動化或腳本裡呼叫它。它不會變成實體,儀表板上看不到它
    • command_line —— 執行指令並讀取輸出,把輸出變成一個實體(感測器、二元感應器、開關、窗簾、通知)。它會定期自己跑


    判斷方法只有一句:你在乎輸出嗎? 在乎 → command_line。不在乎、只是要它去做一件事 → shell_command。

    第二步:那件會改變一切的事 —— 有沒有範本

    這一步是整篇最重要的一段,而且幾乎所有舊教學都寫錯了。

    shell_command 有兩種執行模式,它自己決定要用哪一種:
    1. 指令裡沒有 {{ }}  → 交給 shell 執行
    2.                     管線 |、重導向 > >>、~ 家目錄展開 全部可用
    3. 指令裡有 {{ }}    → 不經過 shell,直接執行那個程式
    4.                     管線、重導向、~ 全部不能用,會被當成一般文字參數
    複製代碼

    官方文件的原話是:用了範本之後,shell_command「runs in a more secure environment that doesn't allow any shell helpers such as automatically expanding the home directory character (~), using pipe symbols (|) to run multiple commands, or operators redirecting output (such as > and >>)」。

    還有一條附帶限制:只有第一個空格之後的內容可以用範本產生,指令名稱本身必須是寫死的字。所以 "{{ my_cmd }} --flag" 這種寫法無效。

    這件事有三個直接後果,每一個都會咬人:

    後果一:帶範本的指令其實是注入安全的。 舊教學說「使用者輸入塞進 shell 指令是命令注入的典型場景」,那對帶範本的 shell_command 不成立 —— 沒有 shell,分號和反引號就只是兩個普通字元。

    後果二:你不能同時要「帶參數」和「用管線」。 這是真正的限制。要兩者兼得,把指令包成一個腳本檔:
    1. #!/bin/bash
    2. # 放在 /config/shell/report.sh,記得 chmod +x
    3. # $1 是第一個參數
    4. df -h "$1" | tail -1 | awk '{print $5}' | tr -d '%'
    複製代碼

    然後在 configuration.yaml 裡:
    1. # /config/configuration.yaml 最外層
    2. shell_command:
    3.   disk_usage: "bash /config/shell/report.sh {{ path }}"
    複製代碼

    管線寫在腳本檔裡,shell_command 只負責把參數傳進去。 這樣兩邊都有了。

    以下還有約 80% 的內容
    登入後即可閱讀完整教學

    登入繼續閱讀使用 Google 登入
    您需要登入後纔可以回帖 登入 | 立即註冊

    本版積分規則

    延伸閱讀

    加入惟家 LINE 群 QR Code加入惟家 LINE 群

    Archiver|手機版|惟家的智能論壇

    GMT+8, 2026-11-10 00:37 , Processed in 0.130974 second(s), 25 queries .

    快速回覆 返回頂部 返回列表