Shell指令碼中文英文多語言國際化和命令列批次處理(bash sh cmd bat)中定義函數的簡單寫法

2023-09-13 12:01:48

有時候為了方便別人使用,我們會選擇去編寫各種各樣的命令列指令碼:給Windows使用者編寫.bat cmd批次處理指令碼,給macOS、Linux使用者編寫.sh bash shell指令碼。

面向國內使用者當然應當首選中文作為指令碼的顯示語言,如果還要支援海外使用者使用,那麼能提供國際化多語言(i18n)支援那是最好了,省事的也許只提供英文版本;i18n這個概念太大了,本篇文章記錄的是如何簡單的實現:根據使用者語言環境,讓指令碼自動顯示成中文或英文,當然如果你願意,同時支援更多語言也是可以的。

命令列指令碼參考 - bat

@echo off
::請儲存成gbk編碼.bat檔案,為了防止亂碼吞掉關鍵字元,所有多位元組字元文字後面均多放了幾個空格  
::取消下面這行註釋可以切換成英文內碼錶cmd視窗  
::chcp 437

::識別當前語言,0英文,1中文,2...更多支援的語言,中文識別簡單粗暴  
set CurrentLang=0
ver | find "版本%qjkTTT%" > nul && set CurrentLang=1

::封裝echo輸出函數,通過2個或更多引數提供不同語言的文字,只顯示當前語言文字  
goto func__echo2
	:echo2
		if "%CurrentLang%"=="1" echo %~1
		if "%CurrentLang%"=="0" echo %~2
	goto:eof
:func__echo2


::測試  
call:echo2 "顯示語言:簡體中文  " "Language: English"
call:echo2 "指令碼執行啦  " "The script is running"
pause

命令列指令碼參考 - bash

#!/usr/bin/env bash
# 請儲存成utf-8編碼.sh檔案,將檔案設為允許執行,然後到終端中執行即可測試

# 識別當前語言,0英文,1中文,2...更多支援的語言
CurrentLang=0
if [ $(echo ${LANG/_/-} | grep -Ei "\\b(zh|cn)\\b") ]; then CurrentLang=1; fi

# 封裝echo輸出函數,通過2個或更多引數提供不同語言的文字,只顯示當前語言文字
function echo2(){
	if [ $CurrentLang == 1 ]; then
		echo $1; #顯示中文
	else
		echo $2; #顯示英文
	fi
}

#測試
echo2 "顯示語言:簡體中文" "Language: English"
echo2 "指令碼執行啦" "The script is running"
read -n1 #按任意鍵退出

以上bat、bash指令碼程式碼參考自GitHub開源庫: https://github.com/xiangyuecn/RSA-csharpTest-Build-Run.batTest-Build-Run.sh 指令碼,無需IDE直接呼叫.NET編譯執行c#程式碼,支援.NET Core、.NET Framework環境下PEM(PKCS#1、PKCS#8)格式RSA金鑰生成、匯入、匯出,多種常見RSA加密、簽名填充演演算法支援。

https://github.com/xiangyuecn/RSA-java ,同樣sh、bat兩個指令碼,無需IDE直接呼叫JDK編譯執行java程式碼,使用bash、bat指令碼程式碼方便好使,也方便參考。

值得學習的知識點

1. 識別終端使用的語言

騷一點的辦法可以直接通過查詢終端的版本號中顯示文字是否包含「版本」這兩個字來判斷是中文環境還是英文環境,bash、bat cmd中均支援,主要是非常簡單(不排除部分情況下使用這種方式判斷出來的結果和實際可能不符)。另外bash裡面可以用$LANG環境變數來判斷,也很好使。

// bat中
> ver  //輸出:Microsoft Windows [版本 10.0.****.***]

//bash中
> bash -version //輸出:GNU bash,版本 5.1.16 ......

2. 函數的編寫

bash本身就支援函數的編寫,所有比較簡單,通過function echo2(){ ... }來定義函數echo2,函數內通過$1 $2 $3 ...來獲取引數。呼叫時直接寫函數名字加引數即可完成函數呼叫:echo2 "args1" args2 args3,引數可以用引號包裹起來(引數內有空格是必須包裹的),沒有引數就直接寫一個函數名字就完成了呼叫:echo2

cmd的bat指令碼裡面沒有專門定義函數的語法,但它支援標籤和goto跳轉,想到哪執行就到哪執行,巨靈活,且標籤支援call:lable呼叫,搭配特殊的標籤eof可以返回到call呼叫點。

因此我們在bat指令碼裡面可以通過:echo2來定義函數入口位置,通過goto:eof來定義函數結束位置,函數內通過%1 %2 %3 ...來獲取引數,%1這種不會去掉引數首尾的引號,使用%~1會去掉首尾的引號。

雖然通過標籤:echo2定義了函數echo2,但bat指令碼執行時會一行一行的執行標籤後面的函數內容,因此我們在:echo2之前要通過goto來跳過函數體,因此我們在函數結尾放一個:func__echo2標籤(標籤名字隨意),函數開頭放一個goto func__echo2,這樣執行的時候就會跳過這個函數體。

最後函數的呼叫,使用call:echo2 "args1" args2 args3來呼叫函數,引數可以用引號包裹起來(引數內有空格是必須包裹的),沒有引數就直接寫一個call:echo2就完成了呼叫。

3. 獲取使用者的輸入

bash中通過read命令來獲取輸入,bat中通過set /p來獲取輸入。

//bat中
set text=&set /p text=^> 

//bash中
read -rp "> " text

上面這個程式碼在不同環境中均會顯示出"> ",然後等待使用者輸入,回車後就會將文字內容存入text變數中;值得要注意的是,bat中如果沒有輸入內容直接回車,變數將不會賦值為空,這個設定比較奇葩,因此需要在輸入前提前把變數設為空,或者輸入之後使用 || set text=來設為空也可以。

4. bat檔案老是亂碼怎麼辦

嘿,bat指令碼這玩意跟隨系統預設編碼,要是utf-8儲存的檔案,中文準要亂碼,得在檔案開頭使用chcp 65001強制切換成utf-8內碼錶,但下指令碼是不亂碼了,但呼叫很多程式命令輸出的內容反而變成了亂碼,還是老實用gbk編碼。

注意到bat檔案內所有多位元組字元文字(中文)後面均特意多寫了幾個空格,這是為了防止在亂碼時換行符、引號等符號被亂碼吞掉(有無作用有待考證),就算bat檔案亂碼了,也能正確執行,並且輸出裡面的英文內容。上面程式碼裡面有個 "版本%qjkTTT%",這個也是一個特殊處理,防止亂碼時結尾的引號被吞掉,錕斤拷 · 燙燙燙 最終抗下了所有。

【完】