問題一:Android Shell 語法格式
結論
Android 系統基於 Linux 內核,但**用戶空間工具極度精簡**。預設 Shell 為 **mksh (MirBSD Korn Shell)**,語法兼容 **POSIX sh** 子集,**不支援 Bash 擴展語法**(陣列、[[ ]]、(( ))、source 等)。
對比表
| 特性 | CentOS (Bash) | Android (mksh/toybox) |
| Shell 執行檔 | /bin/bash | /system/bin/sh (指向 mksh) |
| 支援語法 | Bash 完整語法 | POSIX sh + 部分 ksh 擴展 |
| 常用工具 | GNU Coreutils 完整版 | Toybox/Toolbox 精簡版(參數少、功能減) |
| 腳本開頭 | #!/bin/bash | #!/system/bin/sh |
Android 常用 Shell 命令差異
# 列出檔案
ls -l # Toybox ls 不支援 -h, --color 等參數
# 字串處理
echo ${var//old/new} # mksh 支援,但不如 Bash 完整
# 算術運算
let "a=1+2" # mksh 支援
((a=1+2)) # mksh **不支援**
# 陣列
arr=(1 2 3) # mksh **不支援** 陣列語法
問題二:Shell 子進程與父進程機制
基本概念
- 父 Shell:當前終端機運行的 Shell 進程(PID 如 1000)
- 子 Shell:父 Shell
fork() 出的子進程,繼承父進程環境變數、工作目錄、檔案描述符等**副本**
- 關鍵特性:子 Shell 中的變數修改、
cd 目錄切換、**不影響**父 Shell
產生子 Shell 的常見場景
| 場景 | 示例 | 說明 |
| 管道 | cmd1 | cmd2 | 每個管道段在獨立子 Shell 執行 |
| 命令替換 | var=$(cmd)、`cmd` | 子 Shell 執行 cmd,捕獲輸出 |
| 括號群組 | (cmd1; cmd2) | 在子 Shell 執行群組命令 |
| 後台執行 | cmd & | 子 Shell 後台運行 |
| 腳本執行 | ./script.sh | 新 Shell 進程解釋執行腳本 |
| source/. | source script.sh | **當前 Shell** 執行,**不產生子 Shell**,可修改父環境 |
實戰差異演示
# 父 Shell
var=100
(cd /tmp; var=200; echo "子 Shell var=$var") # 輸出 200
echo "父 Shell var=$var" # 輸出 100(未被修改)
# 管道陷阱
echo "a b c" | read a b c
echo $a $b $c # 空!read 在子 Shell 執行,變數不回傳父 Shell
# 正確寫法:
read a b c <<< "a b c" # Here-string,當前 Shell 執行
# 或
{ read a b c; } <<< "a b c"
多層 Shell 的實際用途
- 權限隔離:普通用戶
su - root 進入 root Shell 執行特權命令,exit 返回普通用戶 Shell
- 環境隔離:
(export PATH=/custom/bin; mycmd) 臨時修改 PATH 不污染父環境
- 腳本模組化:主腳本
source lib.sh 載入函數,子腳本 ./sub.sh 獨立運行
- 容器/虛擬化:Docker
exec -it container bash 進入容器 Shell 命名空間
Android 開發實用技巧
# adb shell 直接進入設備 mksh
adb shell
# 執行單條命令(在子 Shell)
adb shell "ls /data/local/tmp"
# 推送並執行腳本(需執行權限)
adb push script.sh /data/local/tmp/
adb shell "chmod +x /data/local/tmp/script.sh && /data/local/tmp/script.sh"
# 使用 run-as 以應用用戶身份運行(調試私有目錄)
adb shell "run-as com.example.app ls /data/data/com.example.app"
總結:Android Shell 為 **mksh (POSIX sh)**,編寫腳本需避免 Bash 擴展語法;子 Shell 機制核心是「環境副本隔離」,善用 source 避免不必要的子 Shell、管道變數傳遞用 Here-string 或重構邏輯。
- 上一篇文章: MyBatis 插入主鍵衝突異常處理:預檢查 vs 異常捕獲兩種方案對比
- 下一篇文章: JavaScript 事件模型差異:IE srcElement vs Firefox target 的設計哲學解析
Copyright ©
程式碼之家 All Rights Reserved