Shell入門看我吧

背景

以前寫了系列的shell實戰的文章,獲得了挺多小夥伴的關注,遇到有些對shell不太熟悉小夥伴,因此有個想法寫一篇shell入門的文章。
時間流逝,再回頭去看看過去的東西,纔會發現哪些東西比較重要,故撰此文,記錄我在過去學習和使用shell語言過程當中我我的以爲比較重要的部分,作一個小總結和分享。git

文章中使用到的代碼位置: gitee.com/dhar/YTTInj…

gitee.com/dhar/ShellL…github

文章內容結構以下:正則表達式

  • 語法shell

    • 變量
    • 打印
    • 運算
    • 控制
    • 循環
    • 容器
    • 方法
  • 文件數組

    • 文件讀取
    • 文件寫入
  • sed流編輯ruby

  • 模塊bash

    • 工具模塊
    • 流程模塊
  • 輸入和菜單less

    • 獲取輸入
    • 菜單

語法

變量

變量的定義

定義一個變量和其餘語言的相似,shell是弱類型語言因此不須要使用類型限定,而且變量能夠修改類型,下面的例子定義了一個字符串類型的str變量,以後修改成數值類型curl

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

str="string"
echo $str
echo ${str}
str=123
echo $str
複製代碼

變量使用

變量能夠賦值給另外一個變量和打印,當變量被使用的時候須要在變量名稱前面加上$符號,還有另外一種方式是把變量名放在${}括號中使用,能夠把命令執行結果做爲右值賦值給變量

str2=$str
echo $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

複製代碼

打印

由於shell沒有單步調試和其餘功能強大的IDE,因此打印功能就常用到,此外打印功能還能夠當作函數的返回值,比return做爲函數的返回值功能更強大,shell 使用echo打印,內容默認輸出到控制檯中,echo能夠打印字符串、變量、以及字符串中嵌入變量的混個內容,echo有幾重要的參數選項

  • -e 轉義字符處理,好比\t顯示爲製表符而不是顯示輸出\t
  • -n 把文本字符串和命令輸出顯示在同一行中
str4="string4"
echo $str4
echo "str4=$str4"
echo "str4=${str4}str3=${str3}"

# 輸出:
=======打印=======
string4
str4=string4
str4=string4str3=123
複製代碼

運算

使用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
複製代碼

控制

數值比較

控制使用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"
fi

if [[ -z $str1 ]]; then
	echo "str1 爲空"
else
	echo "str1 不爲空"
fi

str1=""
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} 文件不存在"
fi

if [[ -f $file ]]; then
	echo "${file} 是一個文件"
else
	echo "${file} 不是一個文件"
fi

if [[ -d $file ]]; then
	echo "${file} 是一個文件夾"
else
	echo "${file} 不是一個文件夾"
fi

# 輸出:
=======控制文件比較=======
syntax.sh 文件存在
syntax.sh 是一個文件
syntax.sh 不是一個文件夾
複製代碼

循環

C語言格式的for循環

echo "=======循環for======="

num=0
for (( i = 0; i < 10; i++ )); do
	num=$[$num + $i]
done
echo "result = ${num}"

# 輸出:
=======循環for=======
result = 45
複製代碼

for in 循環處理文件

data文件內容以下:

➜  helloshell git:(master) ✗ cat data
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.%     
複製代碼
echo "=======循環for in======="

file="data"
IFS_OLD=$IFS
IFS=$'\n'
for line in $(cat $file)
do
	echo "${line}"
done
IFS=${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=1
while [[ i -lt 10 ]]; do
	i=$(expr $i + 1)
done
複製代碼

until 循環

untilwhile相反,表示條件不知足執行循環,好比下面的例子是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}
複製代碼

容器

數組的定義以下 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

# 一、讀取配置文件內容保存到數組中
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
}
複製代碼

方法

方法的定義有兩種方式

  • 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 invoked
return 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
複製代碼

文件

文件讀取

文件的讀取可使用cat命令結合for in循環處理

注意:IFS是文件循環處理的分隔符,按按行處理數據須要把該值設置爲`'\n'`,處理完成以後恢復舊值

echo "=======文件======="
file="data"
IFS_OLD=$IFS
IFS=$'\n'
for line in $(cat $file)
do
	echo "${line}"
done
IFS=${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.
複製代碼

目錄的讀取

文件的讀取可使用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
複製代碼

文件寫入

使用輸出重定向把內容輸出到文件

  • >輸出重定向符號先清空文件而後把內容寫入到文件中
  • >>輸出重定向符號把內容追加寫入到文件中

此外能夠結合其餘命令實現排序、去重功能

  • sort命令對文件內容以行做爲單位排序
  • uniq命令對文件內容進行去重,以行爲單位,通常須要結合sort命令使用
file="subfolder/data2"
destfile="subfolder/data2-p"
sort ${file} | uniq > ${destfile}

結果:
➜  helloshell git:(master) ✗ cat subfolder/data2
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.%                                                                                          
➜  helloshell git:(master) ✗ cat subfolder/data2-p 
The quick brown
The quick brown fox jumps over the lazy dog.
fox
jumps over the lazy dog.
複製代碼

sed流編輯

Sed流編輯結合正則表達式能夠方便的對文本文件進行查詢、修改、刪除、增長等操做

注意:osx系統自帶的sed命令和標準的gun-sed使用方式上有些差異,因此如下篇幅所談論到的sed都是標準的gun-sed,下面的這個腳本用戶判斷系統是否安裝了gun-sed,若是沒有回自動進行安裝,完成以後須要用戶執行顯示的顯示的命令配置下便可。

# 檢測是否安裝gun sed,mac 內置的sed會有些問題,因此須要安裝gun sed
gunSedInstallCheck() {
	# 檢查是否安裝gunsed
	# mac安裝gunSed 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 "檢測到使用gun 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 gun sed...'
		brew install gnu-sed --with-default-names || exit 1
		# 設置局部環境變量
		echo "set PATH...."
		source ./set-gun-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,將替換的結果寫到文件中。

sed添加內容

如下是injectContentShell#injectedContentShell.sh腳本文件中的代碼片斷,使用a操做吧內容添加到方法的開頭

  • /^- \(.*\){$/這部分是pattern,匹配OC中方法的開始
  • a\ '"$injected_content"'這部分是operation,注意其中插入內容的變量要使用雙引號和單引號包含處理
# 在匹配的行下面添加插入內容
sed -i '/^- \(.*\){$/{ a\ '"$injected_content"' }' ${file}
複製代碼

sed刪除內容

如下是injectContentShell#injectedContentShell.sh腳本文件中的代碼片斷,使用d操做刪除內容

sed -i '/'"$pattern_str"'/ { d }' ${file}
複製代碼

sed修改替換內容

如下是injectContentShell#RenameClasses.sh腳本文件中的代碼片斷,使用s操做替換內容,有如下幾個要點

  • s/'"${original_class_name}"'/'"${result_class_name}"'/g,使用s操做,注意patternreplacement中變量的處理方式,使用雙引號、單引號雙重包含,使用flagg表示所有替換
  • 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}`
複製代碼

模塊

shell是面向過程的語言,不具有面向對象的特性,shell能夠把部分功能獨立分離出來,放在單獨的腳本文件中,其餘模塊能夠導入該腳本文件,使用其中的功能,這就是shell的僞面向對象

工具模塊

工具模塊是包含了工具方法的模塊,好比數學計算能夠放在一個單獨的文件中獨立爲一個模塊,其餘須要使用到的地方引入這個模塊,使用其中定義的方法便可

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

#!/bin/bash 
power(){
	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
複製代碼

流程模塊

流程模塊是包含了一些列操做的模塊,能夠向該模塊傳遞參數,也能夠有返回值。流程模塊中有兩個地方比較特別,一個是流程模塊自己參數的處理方式和外部調用流程模塊傳入參數的方式

流程模塊處理參數

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

#### 參數解析
echo "參數>>${@}"
while getopts :i:o: opt
do
	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";;
	esac
done
echo "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: opt
do
	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";;
	esac
done
echo "param_input_dir = ${param_input_dir}"
echo "param_output_file = ${param_output_file}"


####### 配置

# 屬性黑名單配置文件
blacklist_cfg_file="$(pwd)/DefaultClassesBlackListConfig.cfg"


####### 數據定義

# 定義保存須要處理目標文件的數組
declare -a implement_source_file_array
declare -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
			# 長度小於等於六、註釋內容的行、在黑名單中的內容、分類文件不處理
			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}
複製代碼

輸入和菜單

獲取輸入

下面是一個循環的輸入和檢測輸入是不是合法目錄的例子,是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
}
複製代碼

菜單

在腳本中可能會有使用菜單選項進行交互的場景,有如下幾個要點

  • 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 line

done
複製代碼
相關文章
相關標籤/搜索