歡迎光臨
每天分享高質量文章

20 分鐘 Shell 入門深度教程

作者:aron1992

來源:https://my.oschina.net/FEEDFACF/blog/1789695

0. 背景

之前寫了系列的shell實戰的文章,得到了挺多小夥伴的關註,遇到有些對shell不太熟悉小夥伴,所以有個想法寫一篇shell入門的文章。

時間流逝,再回頭去看看過去的東西,才會發現哪些東西比較重要,故撰此文,記錄我在過去學習和使用shell語言過程中我個人覺得比較重要的部分,做一個小總結和分享。

文章中使用到的程式碼位置:https://gitee.com/dhar/YTTInjectedContentKit/tree/master/DevPods/InjectedContentKit/Example/injectContentShell

https://gitee.com/dhar/ShellLearning/tree/master/helloshell

文章內容結構如下:

  • 語法

    • 變數

    • 列印

    • 運算

    • 控制

    • 迴圈

    • 容器

    • 方法

  • 檔案

    • 檔案讀取

    • 檔案寫入

  • sed流編輯

  • 模組

    • 工具模組

    • 流程模組

  • 輸入和選單

    • 獲取輸入

    • 選單

1. 語法

1.1 變數

變數的定義

定義一個變數和其他語言的類似,shell是弱型別語言所以不需要使用型別限定,並且變數可以修改型別,下麵的例子定義了一個字串型別的str變數,之後修改為數值型別

註意點:變數等號兩邊不能有空格出現

str="string"echo $strecho ${str}str=123echo $str

變數使用

變數可以賦值給另一個變數和列印,當變數被使用的時候需要在變數名稱前面加上$符號,還有另一種方式是把變數名放在${}括號中使用,可以把命令執行結果作為右值賦值給變數

str2=$strecho $str2; str3=${str}echo ${str3}curDir=$(pwd)echo "curDir = ${curDir}"curDirCon=`ls`echo "curDirCon = ${curDir2}"# 輸出:=======變數======= string string 123 123 123 curDir = /Users/aron/git-repo/ShellLearning/helloshell curDirCon = data syntax.sh

1.2 列印

因為shell沒有單步除錯和其他功能強大的IDE,所以列印功能就經常使用到,此外列印功能還可以當做函式的傳回值,比return作為函式的傳回值功能更強大,shell 使用echo列印,內容預設輸出到控制臺中,echo可以列印字串、變數、以及字串中嵌入變數的混個內容,echo有幾重要的引數選項

  • -e 跳脫字元處理,比如\t顯示為製表符而不是顯示輸出\t

  • -n 把文字字串和命令輸出顯示在同一行中

str4="string4"echo $str4echo "str4=$str4"echo "str4=${str4}str3=${str3}"# 輸出:=======列印======= string4 str4=string4 str4=string4str3=123

1.3 運算

使用expr執行算術運算

註意點:*乘法運運算元號需要轉義

echo "=======運算======="result=$(expr 5 + 5)echo ${result}result=$(expr 16 - 5)echo ${result}result=$(expr 5 \* 5)echo ${result}result=$(expr 28 / 5)echo ${result}# 輸出:=======expr運算======= 10 11 25 5

使用[]執行算術

[]執行算術比expr簡單多了,並且*乘法運運算元號不需要轉義

echo "=======[]運算======="result=$[5 + 5]echo ${result}result=$[16 - 5]echo ${result}result=$[5 * 5]echo ${result}result=$[28 / 5]echo ${result}# 輸出:=======[]運算======= 10 11 25 5

1.4 控制

數值比較

控制使用if/else/fi語法,典型的數值比較如下

if [[ 3 > 7 ]]; then echo "hehe"else echo "yes"fi # 輸出: yes

還可以使用下麵的比較符號:

比較符

描述

n1 -eq n2

檢查n1是否與n2相等

n1 -ge n2

檢查n1是否大於或等於n2

n1 -gt n2

檢查n1是否大於n2

n1 -le n2

檢查n1是否小於或等於n2

n1 -lt n2

檢查n1是否小於n2

n1 -ne n2

檢查n1是否不等於n2

一個簡單的9*9乘法口訣表的例子

echo "9*9======="i=1 j=1 line=""while [[ i -lt 10 ]]; do j=1 line="" until [[ j -eq 10 ]]; do if [[ j -le i ]]; then result=$(expr $i \* $j) resultStr="$j X $i = $result" line=${line}${resultStr}"\t" fi j=$(expr $j + 1) done echo -e ${line} i=$(expr $i + 1)done# 輸出:9*9======= 1 X 1 = 1 1 X 2 = 2 2 X 2 = 4 1 X 3 = 3 2 X 3 = 6 3 X 3 = 9 1 X 4 = 4 2 X 4 = 8 3 X 4 = 12 4 X 4 = 16 1 X 5 = 5 2 X 5 = 10 3 X 5 = 15 4 X 5 = 20 5 X 5 = 25 1 X 6 = 6 2 X 6 = 12 3 X 6 = 18 4 X 6 = 24 5 X 6 = 30 6 X 6 = 36 1 X 7 = 7 2 X 7 = 14 3 X 7 = 21 4 X 7 = 28 5 X 7 = 35 6 X 7 = 42 7 X 7 = 49 1 X 8 = 8 2 X 8 = 16 3 X 8 = 24 4 X 8 = 32 5 X 8 = 40 6 X 8 = 48 7 X 8 = 56 8 X 8 = 64 1 X 9 = 9 2 X 9 = 18 3 X 9 = 27 4 X 9 = 36 5 X 9 = 45 6 X 9 = 54 7 X 9 = 63 8 X 9 = 72 9 X 9 = 81 =======  =======

字串比較

比較符

描述

str1 = str2

檢查str1是否和str2相同

str1 != str2

檢查str1是否和str2不同

str1 < str2

檢查str1是否比str2小

str1 > str2

檢查str1是否比str2大

-n str1

檢查str1的長度是否非0

-z str1

檢查str1的長度是否為0

echo "=======控制字串比較======="str1="abc"str2="abd"if [[ $str1 > $str2 ]]; then echo "$str1 大於 $str2"else echo "$str1 小於等於 $str2"fiif [[ -z $str1 ]]; then echo "str1 為空"else echo "str1 不為空"fistr1=""if [[ -z $str1 ]]; then echo "str1 為空"else echo "str1 不為空"fi# 輸出:=======控制字串比較======= abc 小於等於 abd str1 不為空 str1 為空

檔案比較

比較符

描述

-d file

檢查file是否存在並是一個目錄

-e file

檢查file是否存在

-f file

檢查file是否存在並是一個檔案

-r file

檢查file是否存在並可讀

-s file

檢查file是否存在並非空

-w file

檢查file是否存在並可寫

-x file

檢查file是否存在並可執行

-O file

檢查file是否存在並屬當前使用者所有

-G file

檢查file是否存在並且預設組與當前使用者相同

file1 -nt file2

檢查file1是否比file2新

file1 -ot file2

檢查file1是否比file2舊

echo "=======控制檔案比較======="file="syntax.sh"if [[ -e $file ]]; then echo "${file} 檔案存在"else echo "${file} 檔案不存在"fiif [[ -f $file ]]; then echo "${file} 是一個檔案"else echo "${file} 不是一個檔案"fiif [[ -d $file ]]; then echo "${file} 是一個檔案夾"else echo "${file} 不是一個檔案夾"fi# 輸出:=======控制檔案比較======= syntax.sh 檔案存在 syntax.sh 是一個檔案 syntax.sh 不是一個檔案夾

1.5 迴圈

C語言格式的for迴圈

echo "=======迴圈for======="num=0for (( i = 0; i < 10; i++ )); do num=$[$num + $i]doneecho "result = ${num}"# 輸出:=======迴圈for======= result = 45

for in 迴圈處理檔案

data檔案內容如下:

➜  helloshell git:(master) ✗ cat dataThe quick brown fox jumps over the lazy dog.The quick brown fox jumps over the lazy dog.The quick brown fox jumps over the lazy dog.The quick brown fox jumps over the lazy dog.%    

echo "=======迴圈for in======="file="data"IFS_OLD=$IFSIFS=$'\n'for line in $(cat $file)do echo "${line}"doneIFS=${IFS_OLD}# 輸出:=======迴圈for in======= The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog.

while 迴圈

while表示條件滿足執行迴圈,比如下麵的例子是9*9乘法口訣表中的一部分,表示i從1迴圈到9

i=1while [[ i -lt 10 ]]; do i=$(expr $i + 1) done

until 迴圈

until和while相反,表示條件不滿足執行迴圈,比如下麵的例子是9*9乘法口訣表中的一部分,表示j從1迴圈到9

j=1 line="" until [[ j -eq 10 ]]; do if [[ j -le i ]]; then result=$(expr $i \* $j) resultStr="$j X $i = $result" line=${line}${resultStr}"\t" fi j=$(expr $j + 1) done echo -e ${line}

1.6 容器

陣列的定義如下 declare -a array_name

註意:osx系統因為bash的版本太低,只能定義索引陣列,在bash版本高於4.1的版本可以使用declare -A array_name定義關聯陣列

以下的程式碼片定義一個陣列,用於儲存配置檔案中的內容,然後使用for迴圈遍歷陣列內容輸出到控制檯。

  • config_content_array[$cfg_line_count]=$line 把內容儲存到陣列

  • ${#config_content_array[@]} 獲取陣列的元素個數

  • config_content=${config_content_array[i]}; 讀取陣列第i個元素

####### 資料定義# 定義儲存類名稱的陣列declare -a config_content_array cfg_line_count=0# 1、讀取配置檔案內容儲存到陣列中read_config_content_to_array() { # 讀取配置檔案 echo "開始讀取配置檔案..." # mark: p291 IFS_OLD=$IFS IFS=$'\n' # 刪除檔案行首的空白字元 http://www.jb51.net/article/57972.htm for line in $(cat $cfg_file | sed 's/^[ \t]*//g') do is_comment=$(expr "$line" : '^#.*') echo "line=${line} is_common=${is_comment}" if [[ ${#line} -eq 0 ]] || [[ $(expr "$line" : '^#.*') -gt 0 ]]; then echo "blank line or comment line" else config_content_array[$cfg_line_count]=$line cfg_line_count=$[ $cfg_line_count + 1 ] echo "line>>>>${line}" fi done IFS=${IFS_OLD} for (( i = 0; i < ${#config_content_array[@]}; i++ )); do config_content=${config_content_array[i]}; echo "config_content>>>>>>${config_content}" done}

1.7 方法

方法的定義有兩種方式

  • function func1 { #這裡定義方法體 }

  • func2() { #這裡定義方法體 }

方法傳回值的處理有三種方式

  • return 最大傳回256,表示結果碼,有特殊含義,並且只能傳回數值

  • echo 傳回

  • 儲存在全域性變數中

方法的引數

  • 引數的傳遞新增在方法之後,多個使用空格分割

  • 引數的獲取使用$1,$2以此類推,特別地$0表示檔案名、$#表示引數的個數

echo "=======方法======="function func1 { echo "func1 invoked" # 最大的傳回值為256,超過了256取模的結果,280%256=24,最終傳回24 return 280; }func2() { echo "return value"}# 檢測檔案夾存在的方法,結果儲存在全域性變數`CheckInputDestDirRecursiveReturnValue`中# 引數一:檢測的檔案夾路徑# 引數二:提示訊息字串# 使用方式如下,去掉註釋# # 匯入工具指令碼# . ./FileUtil.sh# # 檢測class_search_dir# checkDirCore $class_search_dir "指定類的查詢目錄不存在"# class_search_dir=${CheckInputDestDirRecursiveReturnValue}checkDirCore() { to_process_dir=$1 message=$2 echo "scriptName=${0} paramsCount=${#}" # 需處理原始碼目錄檢查 if [[ -d $to_process_dir ]]; then echo "目錄存在 $to_process_dir" CheckInputDestDirRecursiveReturnValue=$to_process_dir return 1 else echo "${message} ${to_process_dir}" checkInputDestDirRecursive ${to_process_dir} fi}echo `func1`echo `func2` func1 retValue=$?echo "func1 retValue=$retValue"retValue=`func2`echo "func2 retValue=$retValue"checkDirCore $(pwd) "指定類的查詢目錄不存在"dir=${CheckInputDestDirRecursiveReturnValue}echo "dir = ${dir}"# 輸出:=======方法======= func1 invokedreturn value func1 invoked func1 retValue=24 func2 retValue=return value scriptName=./syntax.sh paramsCount=2 目錄存在 /Users/aron/git-repo/ShellLearning/helloshell dir = /Users/aron/git-repo/ShellLearning/helloshell

2. 檔案

2.1 檔案讀取

檔案的讀取可以使用cat命令結合for in迴圈處理

註意:$IFS是檔案迴圈處理的分隔符,按按行處理資料需要把該值設定為$’\n’,處理完成之後恢複舊值

echo "=======檔案======="file="data"IFS_OLD=$IFSIFS=$'\n'for line in $(cat $file)do echo "${line}"doneIFS=${IFS_OLD}輸出: =======檔案======= The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog.

2.2 目錄的讀取

檔案的讀取可以使用ls命令結合for in迴圈處理

echo "=======檔案目錄======="function read_implement_file_recursively { if [[ -d $1 ]]; then for item in $(ls $1); do itemPath="$1/${item}" if [[ -d $itemPath ]]; then # 目錄 echo "處理目錄 ${itemPath}" read_implement_file_recursively $itemPath else # 檔案 echo "處理檔案 ${itemPath}" fi done else echo "err:不是一個目錄" fi}read_implement_file_recursively $(pwd) 輸出: =======檔案目錄======= 處理檔案 /Users/aron/git-repo/ShellLearning/helloshell/data 處理目錄 /Users/aron/git-repo/ShellLearning/helloshell/subfolder 處理檔案 /Users/aron/git-repo/ShellLearning/helloshell/subfolder/data2 處理檔案 /Users/aron/git-repo/ShellLearning/helloshell/syntax.sh

2.3 檔案寫入

使用輸出重定向把內容輸出到檔案

  • >輸出重定向符號先清空檔案然後把內容寫入到檔案中

  • >>輸出重定向符號把內容追加寫入到檔案中

此外可以結合其他命令實現排序、去重功能

  • sort命令對檔案內容以行作為單位排序

  • uniq命令對檔案內容進行去重,以行為單位,一般需要結合sort命令使用

file="subfolder/data2"destfile="subfolder/data2-p"sort ${file} | uniq > ${destfile} 結果: ➜  helloshell git:(master) ✗ cat subfolder/data2The quick brown fox jumps over the lazy dog.The quick brown fox jumps over the lazy dog.The quick brown fox jumps over the lazy dog.The quick brown fox jumps over the lazy dog.%                                                                                           ➜  helloshell git:(master) ✗ cat subfolder/data2-p The quick brownThe quick brown fox jumps over the lazy dog. fox jumps over the lazy dog.

3. Sed流編輯

Sed流編輯結合正則運算式可以方便的對文字檔案進行查詢、修改、刪除、增加等操作

註意:osx系統自帶的sed命令和標準的gnu-sed使用方式上有些差別,所以以下篇幅所談論到的sed都是標準的gnu-sed,下麵的這個指令碼用於判斷系統是否安裝了gnu-sed,如果沒有會自動進行安裝,完成之後需要使用者執行顯示的命令配置下即可。

# 檢測是否安裝gnu sed,mac 內建的sed會有些問題,所以需要安裝gnu sedgnuSedInstallCheck() { # 檢查是否安裝gnused # mac安裝gnuSed  http://blog.csdn.net/sun_wangdong/article/details/71078083 which_sed=`which sed` echo $which_sed echo "testresult = $(expr "$which_sed" : '.*/gnu-sed/')" which_sed=`ls -al ${which_sed}` echo $which_sed echo "testresult = $(expr "$which_sed" : '.*/gnu-sed/')" if [[ $(expr "$which_sed" : '.*/gnu-sed/') -gt 0 ]]; then echo "檢測到使用gnu sed" else if [ ! `which brew` ] then echo 'Homebrew not found. Trying to install...'                    ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" \ || exit 1 fi echo 'Trying to install gnu sed...' brew install gnu-sed --with-default-names || exit 1 # 設定區域性環境變數 echo "set PATH...." source ./set-gnu-sed-path.sh echo "set PATH done" echo "請手動執行命令,然後重新執行" command="PATH=\"/usr/local/Cellar/gnu-sed/4.4/bin:\$PATH\"" echo $command echo "" exit 1 fi}

sed命令功能繁多,所以這裡只講講我在實戰中使用到的,首先瞭解小sed命令的結構

sed -param operation/pattern/replacement/flags

sed param

  • -e script 在處理輸入時,將script中指定的命令新增到已有的命令中

  • -f file 在處理輸入時,將file中指定的命令新增到已有的命令中

  • -n 不產生命令輸出,使用print命令來完成輸出

  • -i 把修改寫入到原檔案中

sed operation

  • s 替換

  • a 追加

  • d 刪除

sed pattern/replacement

查詢對應的樣式和匹配樣式的替換內容

sed flag

有4種可用的替換標記:

  • 數字,表明新文字將替換第幾處樣式匹配的地方;

  • g,表明新文字將會替換所有匹配的文字;

  • p,表明原先行的內容要打印出來;

  • w file,將替換的結果寫到檔案中。

3.1 sed新增內容

以下是injectContentShell#injectedContentShell.sh指令碼檔案中的程式碼片段,使用a操作吧內容新增到方法的開頭

  • /^- \(.*\){$/這部分是pattern,匹配OC中方法的開始

  • a\ ‘”$injected_content”‘這部分是operation,註意其中插入內容的變數要使用雙引號和單引號包含處理

# 在匹配的行下麵新增插入內容sed -i '/^- \(.*\){$/{ a\ '"$injected_content"' }' ${file}

3.2 sed刪除內容

以下是injectContentShell#injectedContentShell.sh指令碼檔案中的程式碼片段,使用d操作刪除內容

sed -i '/'"$pattern_str"'/ { d }' ${file}

3.3 sed修改替換內容

以下是injectContentShell#RenameClasses.sh指令碼檔案中的程式碼片段,使用s操作替換內容,有以下幾個要點

  • s/'”${original_class_name}”‘/'”${result_class_name}”‘/g,使用s操作,註意pattern和replacement中變數的處理方式,使用雙引號、單引號雙重包含,使用flag為g表示全部替換

  • grep ${original_class_name} -rl ${pbxproj_dir},grep命令查詢${pbxproj_dir}檔案夾下所有出現${original_class_name}內容的檔案,-r選項表示遞迴查詢,-l選項表示只顯示匹配到的檔案,傳回的結果可能是多個的。

sed -i '{ s/'"${original_class_name}"'/'"${result_class_name}"'/g }' `grep ${original_class_name} -rl ${pbxproj_dir}` sed -i '{ s/'"${original_class_name}"'/'"${result_class_name}"'/g }' `grep ${original_class_name} -rl ${class_name_replace_dir}`

4. 模組

shell是面向過程的語言,不具備面向物件的特性,shell可以把部分功能獨立分離出來,放在單獨的指令碼檔案中,其他模組可以匯入該指令碼檔案,使用其中的功能,這就是shell的偽面向物件

4.1 工具模組

工具模組是包含了工具方法的模組,比如數學計算可以放在一個單獨的檔案中獨立為一個模組,其他需要使用到的地方引入這個模組,使用其中定義的方法即可

Math.sh儲存了一些數學計算函式

#!/bin/bashpower(){ base=$1 exp=$2 result=1 for (( i = 0; i < $exp; i++ )); do result=$[ $result * $base ]; done echo $result}

其他模組使用. ./Math.sh包含這個模組,可以呼叫其中定義的power方法

註意:. ./Math.sh中.是source的簡寫,這裡也可以寫成source ./Math.sh

echo "=======模組=======". ./Math.sh result=$(power 3 5)echo "3^5 = ${result}"輸出: =======模組======= 3^5 = 243

4.2 流程模組

流程模組是包含了一些列操作的模組,可以向該模組傳遞引數,也可以有傳回值。流程模組中有兩個地方比較特別,一個是流程模組本身引數的處理方式和外部呼叫流程模組傳入引數的方式

流程模組處理引數

流程模組處理引數使用getopts命令實現,getopts optionstring opt其中optionstring格式:i:o:,i和o之後的:表示指定i選項和o選項需要有引數,第一個:表示忽略錯誤,使用case分支處理引數選項對應的引數值。

#### 引數解析echo "引數>>${@}"while getopts :i:o: optdo case "$opt" in i) param_input_dir=$OPTARG echo "Found the -i option, with parameter value $OPTARG" ;; o) param_output_file=$OPTARG echo "Found the -o option, with parameter value $OPTARG" ;; *) echo "Unknown option: $opt";; esacdoneecho "param_input_dir = ${param_input_dir}"echo "param_output_file = ${param_output_file}"

引數的傳遞

引數的傳遞和使用命令列的選項類似,可以在選項後面新增該選項的引數值

./GetAndStoreClasses.sh\ -i ${class_search_dir}\ -o ${cfg_file}

下麵定義的是一個流程模組的指令碼檔案,是injectContentShell#GetAndStoreClasses.sh指令碼檔案中的程式碼片段,實現了生成重新命名的類的配置指令碼功能,可以傳遞兩個引數。

#!/bin/bash######################### 指令碼功能:生成重新命名的類的配置指令碼# 輸入引數 -i 輸入的檔案夾# 輸入引數 -o 儲存的檔案############################### 引數定義param_input_dir=""param_output_file=""####### 引數解析echo "引數>>${@}"while getopts :i:o: optdo case "$opt" in i) param_input_dir=$OPTARG echo "Found the -i option, with parameter value $OPTARG" ;; o) param_output_file=$OPTARG echo "Found the -o option, with parameter value $OPTARG" ;; *) echo "Unknown option: $opt";; esacdoneecho "param_input_dir = ${param_input_dir}"echo "param_output_file = ${param_output_file}"####### 配置# 屬性黑名單配置檔案blacklist_cfg_file="$(pwd)/DefaultClassesBlackListConfig.cfg"####### 資料定義# 定義儲存需要處理標的檔案的陣列declare -a implement_source_file_arraydeclare -a implement_source_file_name_array implement_source_file_count=0# mark: p384# 遞迴函式讀取目錄下的所有.m檔案function read_implement_file_recursively { echo "read_implement_file_recursively" if [[ -d $1 ]]; then for item in $(ls $1); do itemPath="$1/${item}" if [[ -d $itemPath ]]; then # 目錄 echo "處理目錄 ${itemPath}" read_implement_file_recursively $itemPath echo "處理目錄結束=====" else # 檔案 echo "處理檔案 ${itemPath}" if [[ $(expr "$item" : '.*\.m') -gt 0 ]]; then echo ">>>>>>>>>>>>mmmmmmm" implement_source_file_array[$implement_source_file_count]=${itemPath} class_name=${item//".m"/""}; implement_source_file_name_array[$implement_source_file_count]=${class_name} implement_source_file_count=$[ implement_source_file_count + 1 ]; fi echo "" fi done else echo "err:不是一個目錄" fi}post_implement_file_handle() { local wirte_to_file=$1 # 寫入檔案中 echo "# 需要處理的類配置檔案" > ${wirte_to_file} for(( i=0;i<${#implement_source_file_name_array[@]};i++)) do class_file_name=${implement_source_file_name_array[i]}; echo ${class_file_name} >> ${wirte_to_file} done; # 去重 wirte_to_file_bak="${wirte_to_file}.bak" mv ${wirte_to_file} ${wirte_to_file_bak} sort ${wirte_to_file_bak} | uniq > ${wirte_to_file} # 過濾 mv ${wirte_to_file} ${wirte_to_file_bak} echo "# Properties Configs Filtered" > ${wirte_to_file} IFS_OLD=$IFS IFS=$'\n' # 上一行的內容 lastLine=""; for line in $(cat ${wirte_to_file_bak} | sed 's/^[ \t]*//g') do grep_result=$(grep ${line} ${blacklist_cfg_file}) category_judge_substring="\+" if [[ ${#line} -le 6 ]] || [[ $(expr "$line" : '^#.*') -gt 0 ]] || [[ -n ${grep_result} ]] || [[ ${line} =~ ${category_judge_substring} ]]; then # 長度小於等於6、註釋內容的行、在黑名單中的內容、分類檔案不處理 echo "less then 6 char line or comment line" else if [[ -n ${lastLine} ]]; then # 上一行是非空白行 # 比較上一行內容是否是當前行的一部分,不是新增上一行 if [[ ${line} =~ ${lastLine} ]]; then echo "${line}${lastLine} 有交集" else echo ${lastLine} >> ${wirte_to_file} fi fi # 更新上一行 lastLine=${line} fi done IFS=${IFS_OLD} # 刪除臨時檔案 rm -f ${wirte_to_file_bak}}read_implement_file_recursively ${param_input_dir}post_implement_file_handle ${param_output_file}

在另一個模組中使用流程模組

# 獲取需要重新命名的類名稱,儲存到配置檔案中 ./GetAndStoreClasses.sh\ -i ${class_search_dir}\ -o ${cfg_file}

5. 輸入和選單

5.1 獲取輸入

下麵是一個迴圈的輸入和檢測輸入是否是合法目錄的例子,是injectContentShell#FileUtil.sh指令碼檔案中的程式碼片段

  • echo -n “請輸入目錄: “是輸入的提示,-n表示不換行,使用者的輸入跟隨在提示後面

  • read path把使用者的輸入內容儲存在變數path中

# 迴圈檢測輸入的檔案夾checkInputDestDirRecursive() { echo -n "請輸入目錄: " read path if [[ -d $path ]]; then CheckInputDestDirRecursiveReturnValue=$path else echo -n "輸入的目錄無效," checkInputDestDirRecursive fi}

5.2 選單

在指令碼中可能會有使用選單選項進行互動的場景,有以下幾個要點

  • read -n 1 option命令中用了-n選項來限制只讀取一個字元。這樣使用者只需要輸入一個數字,也不用按回車鍵,輸入的內容儲存在option變數中

  • clear命令是用來清空命令列的螢幕的

  • echo -e -e 選項用來處理跳脫字元

  • echo -en -n 選項讓游標處於同一行,使用者的輸入會顯示在同一行

  • 使用while迴圈獲取使用者的輸入,在while迴圈中使用case分支處理不同的操作

以下指令碼是injectContentShell#injectedContentShell.sh檔案中的一部分

function genMunu { clear echo echo -e "\t\t\t選項選單\n" echo -e "\t1. 刪除註入內容" echo -e "\t2. 新增註入內容" echo -e "\t0. Exit menu\n\n" echo -en "\t\tEnter option: " read -n 1 option }while [[ 1 ]]; do genMunu case $option in 0 ) echo "" echo "Bye" exit 0 ;; 1 ) # 刪除配置檔案中註入的內容 removeInjectedContent ;; 2 ) # 新增配置檔案中註入的內容 addInjectedContent ;; h ) genMunu ;; * ) echo "Wrong!!" ;; esac echo echo -en "\n\n\tHit any key to continue" read -n 1 linedone

《Linux雲端計算及運維架構師高薪實戰班》2018年05月14日即將開課中,120天衝擊Linux運維年薪30萬,改變速約~~~~

    *宣告:推送內容及圖片來源於網路,部分內容會有所改動,版權歸原作者所有,如來源資訊有誤或侵犯權益,請聯絡我們刪除或授權事宜。

    – END –


    更多Linux好文請點選【閱讀原文】

    ↓↓↓

    贊(0)

    分享創造快樂