Docker中執行Shell出現亂碼
問題描述
最近遇到一個問題:
執行命令 docker exec f4af9b sh -c ‘bash /tmp/build.sh‘
命令在docker中執行shell,會出現中文亂碼的問題。但是在docker容器中單獨執行shell腳本卻沒有出現亂碼。查看環境變量存在LANG=en_US.UTF-8
,因此從原理上來說是不應該出現亂碼的。
但是既然出現了亂碼,那麽LANG=en_US.UTF-8
應該就沒有讀取到,於是在 build.sh
中運行env
命令,發現通過docker exec f4af9b sh -c ‘bash /tmp/build.sh‘
方式沒有LANG=en_US.UTF-8
環境變量,那麽原因是什麽?
原因定位
原因如下:
docker exec f4af9b sh -c ‘bash /tmp/build.sh‘
對於docker 容器來說是非登錄和非交互式shell,這樣就不會讀取某些配置文件,導致LANG=en_US.UTF-8
沒有加載成功。
Linux Shell
下面介紹一下Linux交互式和非交互式shell、登錄和非登錄shell之間的區別。
- 交互式shell(interactive shell)和非交互式shell(non-interactive shell):
- 交互式的shell會有一個輸入提示符,並且它的標準輸入、輸出和錯誤輸出都會顯示在控制臺上。這種模式也是大多數用戶非常熟悉的:登錄、執行一些命令、退出。當你退出後,shell也終止了。
- 非交互式shell是
bash script.sh
這類的shell。在這種模式下,shell不與你進行交互,而是讀取存放在文件中的命令,並且執行它們。當它讀到文件的結尾EOF,shell也就終止了。
- 交互式的shell會有一個輸入提示符,並且它的標準輸入、輸出和錯誤輸出都會顯示在控制臺上。這種模式也是大多數用戶非常熟悉的:登錄、執行一些命令、退出。當你退出後,shell也終止了。
- 登錄式shell(login shell)和非登陸式shell(no-login shell):
- 需要輸入用戶名和密碼的shell就是登陸式shell。因此通常不管以何種方式登陸機器後用戶獲得的第一個shell就是login shell。不輸入密碼的ssh是公鑰打通的,某種意義上說也是輸入密碼的。
- 非登陸式的就是在登陸後啟動bash等,即不是遠程登陸到主機這種。
對於常用環境變量設置文件,整理出如下加載情況表:
文件 | 非交互+登陸式 | 交互+登陸式 | 交互+非登陸式 | 非交互+非登陸式 |
---|---|---|---|---|
/etc/profile | 加載 | 加載 | - | - |
/etc/bashrc | 加載 | 加載 | - | - |
~/.bash_profile | 加載 | 加載 | - | - |
~/.bashrc | 加載 | 加載 | 加載 | - |
BASH_ENV | - | - | - | 加載 |
執行腳本,如bash script.sh
是屬於non-login + non-interactive。
解決思路
因而,執行命令docker exec f4af9b sh -c ‘bash /tmp/build.sh‘
對於docker容器來說是屬於non-login + non-interactive。
將上面的bash /tmp/build.sh
改為bash --login /tmp/build.sh
變為登錄shell,就可以讀取/etc/profile和~/.bash_profile等文件。
或者在執行bash /tmp/build.sh
時在build.sh
加入export LANG="en_US.UTF-8"
手動設置。
常見的shell變量
PATH:決定了shell將到哪些目錄中尋找命令或程序
HOME:當前用戶主目錄
MAIL:是指當前用戶的郵件存放目錄。
SHELL:是指當前用戶用的是哪種Shell。
HISTSIZE:是指保存歷史命令記錄的條數
LOGNAME:是指當前用戶的登錄名。
HOSTNAME:是指主機的名稱,許多應用程序如果要用到主機名的話,通常是從這個環境變量中來取得的。
LANG/LANGUGE:是和語言相關的環境變量,使用多種語言的用戶可以修改此環境變量。
PS1:是基本提示符,對於root用戶是#,對於普通用戶是$。
PS2:是附屬提示符,默認是">"。
Docker中執行Shell出現亂碼