本篇文章介紹一個(gè)可以通過(guò)命令簡(jiǎn)寫執(zhí)行對(duì)應(yīng)命令的 shell 腳本。
假設(shè)這個(gè) shell 腳本的名稱為 tinyshell.sh。
在 Linux 下進(jìn)行項(xiàng)目開發(fā),經(jīng)常會(huì)用到一些調(diào)試開發(fā)命令。
這些命令可能比較長(zhǎng),需要輸入多個(gè)字符。
例如,Android 系統(tǒng)抓取全部 log 并包含 log 時(shí)間的命令是 adb logcat -b all -v threadtime。
抓取 log 是調(diào)試開發(fā)非常常見的操作,這個(gè)命令又很長(zhǎng),輸入起來(lái)不方便。
為了簡(jiǎn)化輸入,可以配置一些命令簡(jiǎn)寫來(lái)對(duì)應(yīng)比較長(zhǎng)命令。
例如,配置 ala 對(duì)應(yīng) adb logcat -b all -v threadtime。
把 als 作為參數(shù)傳遞給當(dāng)前的 tinyshell.sh 腳本,會(huì)執(zhí)行該命令簡(jiǎn)寫對(duì)應(yīng)的命令。
這樣只需要輸入比較少的字符,就能執(zhí)行比較長(zhǎng)的命令。
實(shí)際上,這個(gè)功能類似于 bash 的 alias 別名,只是將這些別名統(tǒng)一放到該腳本來(lái)處理。
可以把 tinyshell.sh 腳本作為學(xué)習(xí) shell 腳本的參考例子,獨(dú)立維護(hù)更新,根據(jù)需要擴(kuò)充更多的功能。
配置命令簡(jiǎn)寫
如之前說(shuō)明,可以用 ala 表示 adb logcat -b all -v threadtime 這個(gè)命令。
這個(gè) ala 稱之為 “命令簡(jiǎn)寫”。
命令簡(jiǎn)寫使用一些簡(jiǎn)單的字符來(lái)表示特定的命令。
可以在命令簡(jiǎn)寫后面動(dòng)態(tài)提供命令的參數(shù)。
為了方便動(dòng)態(tài)添加、刪除、查詢命令簡(jiǎn)寫,可以把這些命令簡(jiǎn)寫保存在一個(gè)配置文件里面。
在執(zhí)行 tinyshell.sh 腳本時(shí),會(huì)讀取配置文件內(nèi)容,獲取到各個(gè)配置項(xiàng)的值。
配置項(xiàng)的基本格式是:命令簡(jiǎn)寫|命令內(nèi)容
每個(gè)配置項(xiàng)占據(jù)一行。每一行默認(rèn)以第一個(gè)豎線 ‘|' 隔開命令簡(jiǎn)寫和命令內(nèi)容。
一個(gè)參考的配置文件內(nèi)容如下所示:
ll|ls --color=auto -l
ala|adb logcat -b all -v threadtime
gl|git log
gp|git pull --stat --no-tags $(git remote) $(git rev-parse --abbrev-ref HEAD)
這里配置的命令內(nèi)容可以是系統(tǒng)支持的任意命令。
解析配置文件時(shí),需要用到之前文章介紹的 parsecfg.sh 腳本。
要獲取 parsecfg.sh 腳本的代碼,可以查看之前的文章。
后面會(huì)提供具體測(cè)試的例子,可供參考。
腳本代碼
列出 tinyshell.sh 腳本的具體代碼如下所示。
在這個(gè)代碼中,對(duì)大部分關(guān)鍵代碼都提供了詳細(xì)的注釋,方便閱讀。
這篇文章的后面也會(huì)對(duì)一些關(guān)鍵點(diǎn)進(jìn)行說(shuō)明,有助理解。
#!/bin/bash -i
# 使用 bash 的 -i 選項(xiàng),讓該腳本在交互模式下運(yùn)行.
# 實(shí)現(xiàn)一個(gè)小型的 shell. 支持內(nèi)置命令、命令簡(jiǎn)寫. 如果提供這兩種命令之外
# 的其他命令,會(huì)嘗試在 bash 中直接執(zhí)行所給命令,可以執(zhí)行系統(tǒng)支持的命令.
# 命令簡(jiǎn)寫指的是一些簡(jiǎn)單的字符,會(huì)對(duì)應(yīng)一串實(shí)際要執(zhí)行的命令.只要輸入命令
# 簡(jiǎn)寫就可以執(zhí)行對(duì)應(yīng)的命令,減少需要輸入的字符.命令簡(jiǎn)寫在配置文件中配置.
# 下面變量指定默認(rèn)解析的配置文件名.該文件配置了命令簡(jiǎn)寫、以及對(duì)應(yīng)的命令.
# 這個(gè) tinyshellcmds.txt 文件需要預(yù)先配置好,放到指定路徑的目錄底下.
# 直接修改這個(gè)配置文件,就可以動(dòng)態(tài)添加或刪除命令簡(jiǎn)寫.不需要修改腳本代碼.
SHORT_COMMANDS="${HOME}/.liconfig/tinyshellcmds.txt"
# PARSECFG_filepath 是 parsecfg.sh 腳本里面的變量. 如果這個(gè)變量為空,
# 說(shuō)明還沒(méi)有打開過(guò)配置文件,進(jìn)入下面的分支打開默認(rèn)的配置文件.
if [ -z "$PARSECFG_filepath" ]; then
# 導(dǎo)入解析配置文件的腳本,以便調(diào)用該腳本的函數(shù)來(lái)解析配置文件.
source parsecfg.sh
# 調(diào)用 parsecfg.sh 里面的 open_config_file() 函數(shù)解析配置文件.
# 如果配置文件不存在,會(huì)返回 1,經(jīng)過(guò)'!'操作符取反為 0,會(huì)退出執(zhí)行.
if ! open_config_file "$SHORT_COMMANDS"; then
exit 2
fi
fi
# 下面變量指定 tiny shell 的提示字符串.
PROMPT="TinySh>>> "
# 下面使用 basename 命令來(lái)提取出腳本的文件名,去掉目錄路徑部分.
show_help()
{
printf "USAGE
$(basename $0) [option] [shortcmd [argument1 ... [argumentn]]]
OPTIONS
option: 可選的選項(xiàng)參數(shù). 支持的選項(xiàng)參數(shù)描述如下:
-h: 打印這個(gè)幫助信息.
-l: 打印配置文件本身的內(nèi)容,會(huì)列出配置的命令簡(jiǎn)寫和對(duì)應(yīng)的命令.
-v: 以鍵值對(duì)的方式列出命令簡(jiǎn)寫和對(duì)應(yīng)的命令.
-i: 在配置文件中查找指定內(nèi)容.后面跟著一個(gè)參數(shù),指定要查找的內(nèi)容.
-e: 使用 vim 打開腳本的配置文件,以供編輯.
-a: 新增或修改一個(gè)命令簡(jiǎn)寫和對(duì)應(yīng)的命令.后面跟著一個(gè)參數(shù),用
單引號(hào)括起來(lái),以指定命令簡(jiǎn)寫和命令. 格式為: 命令簡(jiǎn)寫|命令.
例如 -a 'p|git pull',如果p簡(jiǎn)寫不存在則新增它,否則修改它.
-d: 從腳本配置文件中刪除一個(gè)命令簡(jiǎn)寫和對(duì)應(yīng)的命令.后面跟著一個(gè)
參數(shù),指定要?jiǎng)h除的命令簡(jiǎn)寫.例如 -d s,會(huì)刪除命令簡(jiǎn)寫為 s 的行.
shortcmd: 可選選項(xiàng).
指定要直接執(zhí)行的命令簡(jiǎn)寫. 提供命令簡(jiǎn)寫參數(shù),不會(huì)進(jìn)入 tiny shell.
argument1 ... argumentn: 可選選項(xiàng).
指定該命令簡(jiǎn)寫的參數(shù). 命令簡(jiǎn)寫對(duì)應(yīng)一個(gè)命令,支持動(dòng)態(tài)提供參數(shù).
NOTE
如果沒(méi)有提供任何參數(shù),默認(rèn)會(huì)進(jìn)入 tiny shell 解釋器. 在 tiny shell 中
接收用戶輸入并執(zhí)行對(duì)應(yīng)的命令.直到讀取到EOF、或者執(zhí)行quit命令才會(huì)退出.
"
}
# tiny shell 的內(nèi)置命令數(shù)組. 這是一個(gè)關(guān)聯(lián)數(shù)組. 數(shù)組元素的
# 鍵名是內(nèi)置命令名. 數(shù)組元素的鍵值是響應(yīng)內(nèi)置命令的函數(shù)名.
declare -A BUILTIN_COMMAND=( \
[help]="builtin_command_help" \
[quit]="builtin_command_quit" \
[debug]="builtin_command_debug" \
)
# bash 的 help 命令默認(rèn)會(huì)打印內(nèi)置命令列表. 這里仿照這個(gè)行為,
# 讓 help 內(nèi)置命令打印內(nèi)置命令列表、以及配置文件包含的命令簡(jiǎn)寫.
builtin_command_help()
{
printf "下面列出 Tiny Shell 支持的內(nèi)置命令列表和配置的命令簡(jiǎn)寫列表.
輸入內(nèi)置命令名或命令簡(jiǎn)寫,會(huì)執(zhí)行對(duì)應(yīng)的命令.
也可以輸入系統(tǒng)自身支持的命令,會(huì)在 bash 中執(zhí)行所給命令.
內(nèi)置命令列表:
debug: 所給第一個(gè)參數(shù)指定打開、或關(guān)閉調(diào)試功能. 其參數(shù)說(shuō)明如下:
on: 打開調(diào)試功能,會(huì)執(zhí)行 bash 的 set -x 命令
off: 關(guān)閉調(diào)試功能,會(huì)執(zhí)行 bash 的 set +x 命令
help: 打印當(dāng)前幫助信息.
quit: 退出當(dāng)前 Tiny Shell.
命令簡(jiǎn)寫列表:
"
# 調(diào)用 parsecfg.sh 的 handle_config_option -v 打印命令簡(jiǎn)寫列表
handle_config_option -v
}
# quit 內(nèi)置命令. 執(zhí)行該命令會(huì)退出整個(gè)腳本,從而退出當(dāng)前 tiny shell.
builtin_command_quit()
{
exit
}
# debug 內(nèi)置命令. 所給第一個(gè)參數(shù)指定打開、或關(guān)閉調(diào)試功能.
# debug on: 打開調(diào)試功能,會(huì)執(zhí)行 bash 的 set -x 命令
# debug off: 關(guān)閉調(diào)試功能,會(huì)執(zhí)行 bash 的 set +x 命令
builtin_command_debug()
{
if [ $# -ne 1 ]; then
echo "Usage: debug on/off"
return 1
fi
if [ "$1" == "on" ]; then
set -x
elif [ "$1" == "off" ]; then
set +x
else
echo -e "Unknown argument: $1\nUsage: debug on/off"
fi
return
}
# 處理 tiny shell 內(nèi)置命令.對(duì)于內(nèi)置命令,會(huì)調(diào)用對(duì)應(yīng)函數(shù)進(jìn)行處理.
# 該函數(shù)的返回值表示所給命令名是否內(nèi)置命令.
# 返回 0, 表示是內(nèi)置命令. 返回 1, 表示不是內(nèi)置命令.
execute_builtin_command()
{
# 在傳遞過(guò)來(lái)的參數(shù)中,第一個(gè)參數(shù)是命令名,剩余的參數(shù)是該命令的參數(shù).
local cmdname="$1"
# 從 BUILTIN_COMMAND 數(shù)組中獲取所給命令對(duì)應(yīng)的處理函數(shù).
# 如果所給命令不是內(nèi)置命令,會(huì)獲取為空.
local cmdfunc="${BUILTIN_COMMAND["${cmdname}"]}"
if [ -n "${cmdfunc}" ]; then
# 將位置參數(shù)左移一位,移除命令名,剩下的就是該命令的參數(shù).
shift 1
${cmdfunc} "$@"
# 無(wú)論執(zhí)行內(nèi)置命令是否報(bào)錯(cuò),都會(huì)返回 0,表示該命令是內(nèi)置命令.
return 0
else
return 1
fi
}
# 處理 tiny shell 的命令簡(jiǎn)寫.在所解析的配置文件中包含了支持的命令簡(jiǎn)寫.
# 該函數(shù)的返回值表示所給命令名是否命令簡(jiǎn)寫.
# 返回 0, 表示是命令簡(jiǎn)寫. 返回 1, 表示不是命令簡(jiǎn)寫.
execute_short_command()
{
# 判斷所給的參數(shù)是否對(duì)應(yīng)配置文件中的某個(gè)鍵名.如果是,將取出鍵值.
local key="$1"
# 從配置文件中獲取所給命令簡(jiǎn)寫對(duì)應(yīng)要執(zhí)行的命令
local cmd_value=$(get_value_by_key "${key}")
if test -n "${cmd_value}"; then
# 將位置參數(shù)左移一位,移除命令簡(jiǎn)寫,剩下的就是命令的參數(shù).
shift 1
# 下面要用 "$*" 來(lái)把所有參數(shù)組合成一個(gè)參數(shù),再跟命令內(nèi)容一起傳入
# bach -c,確保 bash -c 把命令內(nèi)容和所有參數(shù)都當(dāng)成要執(zhí)行的命令
bash -c "$cmd_value $*"
# 打印命令簡(jiǎn)寫,以及該簡(jiǎn)寫對(duì)應(yīng)的命令,以便查看具體執(zhí)行了什么命令.
# 先執(zhí)行命令,再打印命令內(nèi)容. 由于有些命令的輸出很多,先打印命令
# 內(nèi)容的話,需要拉動(dòng)終端滾動(dòng)條,才能找到打印的命令內(nèi)容,不便于查看.
echo -e "\e[33m命令簡(jiǎn)寫: ${key}. 命令: ${cmd_value} $*\e[0m"
return 0
else
# 如果獲取到的鍵值為空,表示所給鍵名不是有效的命令簡(jiǎn)寫,返回 1
return 1
fi
}
# 處理所給的內(nèi)容.這個(gè)內(nèi)容可能是內(nèi)置命令,命令簡(jiǎn)寫,或者命令本身.
handle_input_command()
{
# 所給參數(shù)是要執(zhí)行的命令名、以及命令參數(shù). 如果命令名是配置的
# 命令簡(jiǎn)寫,會(huì)把該命令簡(jiǎn)寫替換成對(duì)應(yīng)的命令,再進(jìn)行對(duì)應(yīng)的命令.
local inputcmd="$@"
# if 語(yǔ)句可以直接判斷命令返回值是否為 0,并不是只能搭配 [ 命令使用.
# 注意: 由于有的 tiny shell 內(nèi)置命令接收參數(shù),下面的 ${cmd_line}
# 不能用雙引號(hào)括起來(lái),否則多個(gè)參數(shù)會(huì)被當(dāng)成一個(gè)參數(shù).
if execute_builtin_command ${inputcmd}; then
# 先調(diào)用 execute_builtin_command 函數(shù)處理內(nèi)置命令.如果所給
# 命令是內(nèi)置命令,則調(diào)用對(duì)應(yīng)的函數(shù)進(jìn)行處理,且不再往下執(zhí)行.
return 0
elif execute_short_command ${inputcmd}; then
# 調(diào)用 execute_short_command 函數(shù)處理命令簡(jiǎn)寫.
return 0
else
# 對(duì)于 tiny shell 不能執(zhí)行的命令,嘗試用 bash -c 在 bash 中執(zhí)行.
bash -c "${inputcmd}"
# 當(dāng) return 命令不加具體狀態(tài)碼時(shí),它會(huì)返回上一條執(zhí)行命令的狀態(tài)碼.
return
fi
}
# SIGINT 信號(hào)的處理函數(shù).目前不做特殊處理,只是想在輸入CTRL-C后,不會(huì)終止
# 當(dāng)前 tiny shell. 輸入 CTRL-C 還是可以終止 tiny shell 啟動(dòng)的子 shell.
sigint_handler()
{
# 當(dāng)輸入 CTRL-C 后,終端只顯示"^C",但是不會(huì)自動(dòng)換行,需要輸入回車才會(huì)
# 換行,并重新輸出提示字符串. 而在交互式Bash中,輸入"^C"后,就會(huì)自動(dòng)回
# 車,并輸出提示字符串.這里模仿這個(gè)行為,先輸出一個(gè)回車,再輸出提示符.
printf "\n${PROMPT}"
}
# 啟動(dòng) tiny shell 解釋器. 從標(biāo)準(zhǔn)輸入不停讀取、并執(zhí)行所給命令.直到
# 使用 CTRL-D 輸入 EOF 為止, 或者輸入 quit 命令退出當(dāng)前解釋器.
start_tinyshell()
{
# 執(zhí)行 python 命令,默認(rèn)會(huì)打印 python 版本號(hào)和一句幫助提示.
# 這里仿照這個(gè)行為,打印 tiny shel 版本號(hào)和一句幫助提示.
echo -e "Tiny shell 1.0.0\nType 'help' for more information."
# 捕獲SIGINT信號(hào),以便輸入 CTRL-C 后,不會(huì)退出當(dāng)前的 tiny shell.
# 注意: 由于子shell會(huì)繼承父shell所忽略的信號(hào),所以不能將 SIGINT 信號(hào)
# 設(shè)成忽略,而是要指定一個(gè)處理函數(shù). 當(dāng)前 shell 所捕獲的信號(hào)不會(huì)被
# 子 shell 繼承. 所以子 shell 還是可以被 CTRL-C 終止. 即,指定信號(hào)處理
# 函數(shù)后,當(dāng)前 tiny shell 不會(huì)被CTRL-C終止.但是當(dāng)前 tiny shell 執(zhí)行的
# 命令會(huì)運(yùn)行在子 shell 下,可以用 CTRL-C 終止運(yùn)行在子 shell 下的命令.
# 查看 man bash 對(duì)子 shell 的信號(hào)繼承關(guān)系說(shuō)明如下:
# traps caught by the shell are reset to the values inherited from
# the shell's parent, and traps ignored by the shell are ignored
trap "sigint_handler" SIGINT
# 如果不使用 -e 選項(xiàng),輸入上光標(biāo)鍵, read 會(huì)讀取到 "^[[A";輸入下光標(biāo)鍵,
# read 會(huì)讀取到 "^[[B".而使用 -e 選項(xiàng)后,輸入上下光標(biāo)鍵,不會(huì)讀取到亂碼,
# 但是在子shell中,也不會(huì)返回歷史命令.因?yàn)閟hell腳本是在非交互模式下執(zhí)行.
# 可以使用 bash 的 -i 選項(xiàng)讓腳本在交互模式下運(yùn)行,例如: "#/bin/bash -i"
while read -ep "${PROMPT}" input; do
# 傳遞參數(shù)給函數(shù)時(shí),參數(shù)要用雙引號(hào)括起來(lái),避免參數(shù)帶有空格時(shí),會(huì)拆分
# 成多個(gè)參數(shù). 當(dāng)輸入CTRL-C時(shí), tiny shell 捕獲了這個(gè)信號(hào),不會(huì)退出
# 當(dāng)前的 tiny shell.但是read命令會(huì)被中斷,此時(shí)讀取到的 input 為空.
# 不需要對(duì)空行做處理,所以下面先判斷 input 變量值是否為空.
if [ -n "${input}" ]; then
handle_input_command "${input}"
# 執(zhí)行 history -s 命令把所給的參數(shù)添加到當(dāng)前歷史記錄中.后續(xù)
# 通過(guò)上下光標(biāo)鍵獲取歷史命令,就可以獲取到新添加的命令.這個(gè)只
# 影響當(dāng)前 tiny shell 的歷史記錄,不會(huì)寫入外部shell的歷史記錄.
history -s "${input}"
fi
done
# 輸出一個(gè)換行.當(dāng)用戶輸入CTRL-D結(jié)束執(zhí)行后,需要換行顯示原先的終端提示符.
echo
}
# 循環(huán)調(diào)用 getopts 命令處理選項(xiàng)參數(shù).
while getopts "hlvi:ea:d:" opt; do
# 調(diào)用parsecfg.sh腳本處理選項(xiàng)的函數(shù)來(lái)處理 "lvi:ea:d:" 這幾個(gè)選項(xiàng).
# 如果處理成功,就直接繼續(xù)讀取下一個(gè)選項(xiàng),不再往下處理.
# handle_config_option()函數(shù)要求傳入的選項(xiàng)以'-'開頭,而getopts命令
# 返回的選項(xiàng)不帶有'-',所以下面在 ${opt} 前面加上一個(gè) '-'.
handle_config_option "-${opt}" "${OPTARG}"
if [ $? -ne 127 ]; then
continue
fi
case "$opt" in
h) show_help ;;
?) echo "出錯(cuò): 異常選項(xiàng),請(qǐng)使用 -h 選項(xiàng)查看腳本的幫助說(shuō)明." ;;
esac
done
# $# 大于0,說(shuō)明提供了命令參數(shù). $# 等于OPTIND減去1,說(shuō)明傳入的參數(shù)都
# 是以 '-' 開頭的選項(xiàng)參數(shù). 此時(shí),直接結(jié)束執(zhí)行,不需要再往下處理.
# 下面的 -a 表示兩個(gè)表達(dá)式都為真時(shí)才為真.表達(dá)式之間不要加小括號(hào).
# Shell里面的小括號(hào)有特殊含義,跟C語(yǔ)言的小括號(hào)有些區(qū)別,加上會(huì)有問(wèn)題.
if [ $# -gt 0 -a $# -eq $((OPTIND-1)) ]; then
exit 0
fi
if [ $# -eq 0 ]; then
# 當(dāng)不帶任何參數(shù)時(shí),默認(rèn)啟用 tiny shell.
start_tinyshell
else
# 左移所給的命令參數(shù),去掉已處理過(guò)的選項(xiàng)參數(shù),只剩下非選項(xiàng)參數(shù).
shift $((OPTIND-1))
# 執(zhí)行腳本時(shí),如果提供了非選項(xiàng)參數(shù),那么第一個(gè)參數(shù)認(rèn)為是命令簡(jiǎn)寫,
# 需要執(zhí)行該命令簡(jiǎn)寫對(duì)應(yīng)的命令. 第一個(gè)參數(shù)之后的所有參數(shù)認(rèn)為是
# 命令的參數(shù). 即,可以在命令簡(jiǎn)寫之后提供參數(shù)來(lái)動(dòng)態(tài)指定一些操作.
execute_short_command "$@"
fi
exit
代碼關(guān)鍵點(diǎn)說(shuō)明
使用 trap 命令捕獲信號(hào)
在 bash 中,可以使用 trap 命令捕獲信號(hào),并指定信號(hào)處理函數(shù)。
捕獲信號(hào)后,可以避免收到某個(gè)信號(hào)終止腳本執(zhí)行。
當(dāng)前 tinyshell.sh 腳本使用 trap 命令捕獲 SIGINT 信號(hào)。
也就是 CTRL-C 鍵所發(fā)送的信號(hào),避免按 CTRL-C 鍵會(huì)退出當(dāng)前 tiny shell。
要注意的是,不能設(shè)置成忽略 SIGINT 信號(hào)。
在 bash 中,父 shell 所忽略的信號(hào),也會(huì)被子 shell 所忽略。
除了內(nèi)置命令之外,當(dāng)前 tiny shell 所執(zhí)行的命令運(yùn)行在子 shell 下。
如果設(shè)置成忽略 SIGINT 信號(hào),那么子 shell 也會(huì)忽略這個(gè)信號(hào)。
那么就不能用 CTRL-C 來(lái)終止子 shell 命令的執(zhí)行。
例如,Android 系統(tǒng)的 adb logcat 命令會(huì)不停打印 log,需要按 CTRL-C 來(lái)終止。
此時(shí),在 tiny shell 里面按 CTRL-C 就不能終止 adb logcat 的執(zhí)行。
父 shell 所捕獲的信號(hào),子 shell 不會(huì)繼承父 shell 所捕獲的信號(hào)。
子 shell 會(huì)繼承父 shell 的父進(jìn)程的信號(hào)狀態(tài)。
父 shell 的父進(jìn)程一般是外部 bash shell 進(jìn)程。
而 bash shell 進(jìn)程默認(rèn)捕獲SIGINT并終止前臺(tái)進(jìn)程。
即,雖然當(dāng)前 tiny shell 捕獲了 SIGINT 信號(hào),但是子 shell 并沒(méi)有捕獲該信號(hào)。
可以在 tiny shell 使用 CTRL-C 來(lái)終止子 shell 命令的執(zhí)行。
使用 history -s 命令添加歷史記錄
在 tiny shell 執(zhí)行命令后,默認(rèn)不能用上下光標(biāo)鍵查找到 tiny shell 自身執(zhí)行的歷史命令。
為了可以查找到 tiny shell 自身執(zhí)行的歷史命令,使用 history -s 命令添加命令到當(dāng)前 shell 的歷史記錄。
這個(gè)命令只會(huì)影響當(dāng)前 shell 的歷史記錄。
退出當(dāng)前 shell 后,在外部 shell 還是看不到 tiny shell 所執(zhí)行的命令。
由于這個(gè) tiny shell 主要是為了執(zhí)行命令簡(jiǎn)寫。
這些命令簡(jiǎn)寫只有 tiny shell 自身支持,不需要添加到 bash shell 的歷史記錄。
如果想要命令歷史信息添加到外部 shell 的歷史記錄,可以在退出 tinyshell.sh 腳本之前,執(zhí)行 history -w ~/.bash_history 命令把歷史記錄寫入到 bash 自身的歷史記錄文件。
測(cè)試?yán)?br />
把 tinyshell.sh 腳本放到 PATH 變量指定的可尋址目錄下。
查看 tinyshell.sh 腳本代碼,可知要解析的配置文件名是 tinyshellcmds.txt。
把前面貼出的命令簡(jiǎn)寫配置信息寫入 tinyshellcmds.txt 文件。
把這個(gè)文件放到 HOME 目錄的 .liconfig 目錄下。
之后,就可以開始執(zhí)行 tinyshell.sh 腳本。
當(dāng)前的 tinyshell.sh 腳本可以執(zhí)行內(nèi)置命令、命令簡(jiǎn)寫對(duì)應(yīng)的命令、系統(tǒng)自身支持的命令。
當(dāng)不提供任何命令參數(shù)時(shí),會(huì)進(jìn)入 tiny shell。
在 tiny shell 中,會(huì)不停接收用戶輸入并執(zhí)行對(duì)應(yīng)命令。
直到讀取到 EOF 、或者執(zhí)行 quit 命令才會(huì)退出 tiny shell。
處理選項(xiàng)參數(shù)和直接處理命令簡(jiǎn)寫的例子
下面是不進(jìn)入 tiny shell,只處理選項(xiàng)參數(shù)和命令簡(jiǎn)寫的例子:
$ tinyshell.sh -v
key='gl' value='git log'
key='gp' value='git pull --stat --no-tags $(git remote) $(git rev-parse --abbrev-ref HEAD)'
key='ll' value='ls --color=auto -l'
key='ala' value='adb logcat -b all -v threadtime'
$ tinyshell.sh ll
-rwxrwxr-x 1 xxx xxx 964 11月 14 17:37 tinyshell.sh
命令簡(jiǎn)寫: ll. 命令: ls --color=auto -l
這里先執(zhí)行 tinyshell.sh -v 命令,用鍵值對(duì)的形式列出支持的命令簡(jiǎn)寫。
此時(shí),只處理所給的選項(xiàng)參數(shù),不會(huì)進(jìn)入 tiny shell 里面。
tinyshell.sh ll 命令,提供了一個(gè) ll 參數(shù)(兩個(gè)小寫字母 l)。
這個(gè)參數(shù)會(huì)被當(dāng)成命令簡(jiǎn)寫,然后執(zhí)行該命令簡(jiǎn)寫對(duì)應(yīng)的命令。
執(zhí)行結(jié)束后,不會(huì)進(jìn)入 tiny shell 里面。
基于剛才列出的命令簡(jiǎn)寫,可知 ll 對(duì)應(yīng) ls --color=auto -l 命令。
實(shí)際執(zhí)行的也是這個(gè)命令。
進(jìn)入 tiny shell 循環(huán)處理命令的例子
當(dāng)不提供任何命令參數(shù)時(shí),會(huì)進(jìn)入 tiny shell 里面,循環(huán)處理命令。
具體例子如下所示:
$ tinyshell.sh
Tiny shell 1.0.0
Type 'help' for more information.
TinySh>>> help
下面列出 Tiny Shell 支持的內(nèi)置命令列表和配置的命令簡(jiǎn)寫列表.
輸入內(nèi)置命令名或命令簡(jiǎn)寫,會(huì)執(zhí)行對(duì)應(yīng)的命令.
也可以輸入系統(tǒng)自身支持的命令,會(huì)在 bash 中執(zhí)行所給命令.
內(nèi)置命令列表:
debug: 所給第一個(gè)參數(shù)指定打開、或關(guān)閉調(diào)試功能. 其參數(shù)說(shuō)明如下:
on: 打開調(diào)試功能,會(huì)執(zhí)行 bash 的 set -x 命令
off: 關(guān)閉調(diào)試功能,會(huì)執(zhí)行 bash 的 set +x 命令
help: 打印當(dāng)前幫助信息.
quit: 退出當(dāng)前 Tiny Shell.
命令簡(jiǎn)寫列表:
key='gl' value='git log'
key='gp' value='git pull --stat --no-tags $(git remote) $(git rev-parse --abbrev-ref HEAD)'
key='ll' value='ls --color=auto -l'
key='ala' value='adb logcat -b all -v threadtime'
TinySh>>> date
2019年 12月 31日 星期二 17:46:41 CST
TinySh>>> ll -C
tinyshell.sh
命令簡(jiǎn)寫: ll. 命令: ls --color=auto -l -C
當(dāng)執(zhí)行 tinyshell.sh 命令會(huì)進(jìn)入 tiny shell 時(shí),會(huì)打印一個(gè) “TinySh>>>” 提示符。
在 tiny shell 中執(zhí)行 help 命令可以查看支持的內(nèi)置命令和命令簡(jiǎn)寫。
在 tiny shell 中執(zhí)行 date 命令打印當(dāng)前的日期和時(shí)間。
當(dāng)前的 tiny shell 自身不支持 date 命令。
這里執(zhí)行了系統(tǒng)自身的 date 命令。
最后執(zhí)行 ll -C 命令。
這里的 ll 是命令簡(jiǎn)寫。后面的 -C 是對(duì)應(yīng)命令的參數(shù)。
具體執(zhí)行的命令是 ls --color=auto -l -C。
ls 命令的 -C 選項(xiàng)會(huì)多列顯示文件名,覆蓋了 -l 選項(xiàng)的效果。
由于 -l 選項(xiàng)的效果被覆蓋,輸出結(jié)果沒(méi)有打印文件的詳細(xì)信息,只列出文件名。
可以看到,在命令簡(jiǎn)寫之后,可以再提供其他的命令參數(shù)。
即,可以只配置比較長(zhǎng)的命令前綴部分,一些簡(jiǎn)單的參數(shù)可以動(dòng)態(tài)提供。
不需要在配置文件中添加很多內(nèi)容相似、只有細(xì)微差異的配置項(xiàng)。
以上就是分享一個(gè)可以通過(guò)命令簡(jiǎn)寫執(zhí)行對(duì)應(yīng)命令的Shell腳本的詳細(xì)內(nèi)容,更多關(guān)于命令簡(jiǎn)寫執(zhí)行對(duì)應(yīng)命令的Shell腳本的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
您可能感興趣的文章:- 監(jiān)控MySQL主從狀態(tài)的shell腳本
- shell腳本使用兩個(gè)橫杠接收外部參數(shù)的方法
- 使用Shell腳本如何啟動(dòng)/停止Java的jar程序
- Shell中使用grep、sed正則提取和替換字符串
- Shell eval通過(guò)變量獲取環(huán)境變量的方法實(shí)現(xiàn)
- shell腳本實(shí)戰(zhàn)-while循環(huán)語(yǔ)句
- shell腳本--sed的用法詳解
- linux shell中 if else以及大于、小于、等于邏輯表達(dá)式介紹
- Linux中執(zhí)行shell腳本的4種方法總結(jié)
- 一個(gè)不錯(cuò)的shell 腳本教程 入門級(jí)
- Shell字符串比較相等、不相等方法小結(jié)
- python中執(zhí)行shell命令的幾個(gè)方法小結(jié)