hashub

hashub

Shell

超哥 入門

推薦閱讀
https://effective-shell.com

一、基礎#

shell 的作用是

  • 解釋執行使用者輸入的命令或程序等
  • 使用者輸入一條命令,shell 就解釋一條
  • 鍵盤輸入命令,Linux 給予響應的方式,稱之為互動式

shell 的作用_1
shell 的作用_1

shell 是一塊包裹著系統核心的殼,處於操作系統的最外層,與使用者直接對話,把使用者的輸入,解釋給操作系統,然後處理操作系統的輸出結果,輸出到螢幕給予使用者看到結果。

從我們登入 Linux,輸入帳號密碼到進入 Linux 互動式介面,所有的操作,都是交給 shell 解釋並執行

shell 的作用_2
image

1.1 什麼是 shell 腳本#

當命令或者程序語句寫在文件中,我們執行文件,讀取其中的代碼,這個程序文件就稱之為 shell 腳本。

在 shell 腳本裡定義多條 Linux 命令以及循環控制語句,然後將這些 Linux 命令一次性執行完畢,執行腳本文件的方式稱之為,非互動式方式。

windows 中存在 *.bat 批處理腳本

Linux 中常用 *.sh 腳本文件

shell 腳本規則

在 Linux 系統中,shell 腳本或者稱之為 (bash shell 程序)通常都是 vim 編輯,由 Linux 命令、bash shell 指令、邏輯控制語句 和 註釋信息組成。

Shebang#

電腦程序中,shebang 指的是出現在文本文件的第一行前兩個字符 #!

在 Unix 系統中,程序會分析 shebang 後面的內容,作為解釋器的指令,例如

  • #! /bin/sh 開頭的文件,程序在執行的時候會調用 /bin/sh ,也就是 bash 解釋器
  • #!/usr/bin/python 開頭的文件,代表指定 python 解釋器去執行
  • #!/usr/bin/env 解釋器名稱,是一種在不同平台上都能正確找到解釋器的辦法

注意事項:

  • 如果腳本未指定 shebang ,腳本執行的時候,默認用當前 shell 去解釋腳本,即 $SHELL
  • 如果 shebang 指定了可執行的解釋器,如 /bin/bash /usr/bin/python ,腳本在執行時,文件名會作為參數傳遞給解釋器
  • 如果 #! 指定的解釋程序沒有可執行權限,則會報錯 "bad interpreter: Permission denied"
  • 如果 #! 指定的解釋程序不是一個可執行文件,那麼指定的解釋程序會被忽略,轉而交給當前的 SHELL 去執行這個腳本。
  • 如果 #! 指定的解釋程序不存在,那麼會報錯 "bad interpreter: No such file or directory"
  • #! 之後的解釋程序,需要寫其絕對路徑 (如︰#!/bin/bash),它是不會自動到 $PATH 中尋找解釋器的
  • 如果你使用 bash test.sh 這樣的命令來執行腳本,那麼 #! 這一行將會被忽略掉,解釋器當然是用命令行中顯式指定的 bash
#! /bin/bash

# Date: xxx
# Author: xxx
# Blog: xxx

shell 腳本語言很適合處理純文本類型數據,且 Linux 的哲學思想就是一切皆文件,如日誌、配置文件、文本、網頁文件,大多數都是純文本類型的,因此 shell 可以方便的進行文本處理,好比強大的 Linux 三劍客 (grep、sed、awk)

腳本語言#

shell 腳本語言屬於一種 弱類型語言 無需聲明變量類型,直接定義使用

強類型語言,必須先定義變量類型,確定是數字、字符串等,之後再賦予同類型的值

# Linux 默認 shell
[root@localhost ~]# echo $SHELL
/bin/bash

# Centos7 支持的 shell
[root@localhost ~]# cat /etc/shells
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash
/bin/tcsh
/bin/csh

默認的 sh 解釋器

[root@localhost ~]# ll /usr/bin/sh
lrwxrwxrwx. 1 root root 4 Jul 18 19:54 /usr/bin/sh -> bash

1.2 bash#

歷史命令

[root@localhost ~]# echo $HISTSIZE
1000

[root@localhost ~]# echo $HISTFILE
/root/.bash_history


history
-c 清除歷史
-r $HISTFILE 恢復歷史

[root@localhost ~]# history -c
[root@localhost ~]# history
    1  history
[root@localhost ~]# history -r ~/.bash_history


!歷史ID	# 快速執行歷史命令
!!		 # 執行上次的命令

bash 特性

  • 文件路徑 tab 鍵補全
  • 命令補全
  • 快捷鍵 ctrl + a, e, u, k, l
  • 通配符
  • 命令歷史
  • 命令別名
  • 命令行展開

1.3 shell 變量#

變量定義與賦值,注意 == 變量與值之間不得有空格 ==

  • 變量類型,bash 默認把所有變量都認為是字符串
  • bash 變量是弱類型,無需事先聲明類型,是將聲明和賦值同時進行

變量替換 / 引用

name="This is test!"
echo ${name}
echi $name # 可以省略花括號

單引號變量,不識別特殊語法

雙引號變量,能識別特殊符號

變量名規則

  • 名稱定義要做到見名知意,切按照規則來,切不得引用保留關鍵字 (help 檢查保留字)
  • 只能包含數字、字母、下劃線
  • 不能以數字開頭
  • 不能用標點符號
  • 變量名嚴格區分大小寫

變量的作用域

  • 本地變量,只針對當前的 shell 進程
pstree 檢查進程樹

環境變量:也稱為全局變量,針對當前 shell 以及其任意子進程,環境變量也分 自定義、內置 兩種環境變量

局部變量:針對在 shell 函數 或是 shell 腳本 中定義

位置參數變量:用於 shell 腳本中傳遞的參數

特殊變量:shell 內置的特殊功效變量

  • $?
    • 0 : 成功
    • 1 - 255 : 錯誤碼

自定義變量

  • 變量賦值:varName=value
  • 變量引用:${varName} , $varName
  • "" ,變量名會替換變量值

單引號變量,不識別特殊語法

雙引號變量,能識別特殊符號

  1. 每次調用 bash/sh 解釋器執行腳本,都会開啟一個子 shell,因此不保留當前的 shell 變量,通過 pstree 命令檢查進程樹

  2. 調用 source 或者點符號,在當前 shell 環境加載腳本,因此保留變量

# 1. 開啟子 shell 的執行方式
cat make_vars.sh
name="test"

echo $name
aa

bash make_vars.sh

echo $name
aa

# 2. 不開啟子 shell 的執行方式

`Linux 命令`
反引號

echo dir=`ls`
echo $dir
xxxx  xxx 

shell 變量面試題

cat test.sh
user1=`whoami`

sh test.sh

echo $user1
B

A. 當前用戶
B. 空

1.4 環境變量設置#

環境變量一般指的是用 export 內置命令導出的變量,用於定義 shell 的運行環境、保證 shell 命令的正確執行

shell 通過環境變量確定登錄的用戶名、PATH 路徑、文件系統等各種應用

環境變量可以在命令行中臨時創建,但是用戶退出 shell 終端,變量即丟失,如要永久生效,需要修改環境變量配置文件

  • 用戶個人配置文件 ~/.bash_profile ~/.bashrc 遠程登錄用戶特有文件
  • 全局配置文件 /etc/profile/etc/bashrc ,且系統建議最好創建在 /etc/profile.d/ 而非直接修改主文件,修改全局配置文件,影響所有登錄系統的用戶

檢查系統環境變量的命令

  • set : 當前 shell 中的所有變量,包括全局變量、局部變量,包含函數
  • env : 只顯示全局變量
  • declare : 輸出所有的變量,如同 set
  • export : 顯示和設置環境變量值

撤銷環境變量

  • unset 變量名,刪除變量或函數

設置只讀變量

  • readonly ,只有 shell 結束,只讀變量失效

系統保留環境變量關鍵字

bash 內嵌了諸多環境變量,用於定義 bash 的工作環境

export | awk -F '[ :=]' '{print $3}'

bash 多命令執行

ls /data/;cd /tmp/;cd /home;cd /data

環境變量初始化與加載順序

ssh 登錄 linux 後,系統啟動一個 bash shell

/etc/profile : 全局環境變量文件,並從 /etc/profile.d 目錄的配置文件中搜集 shell 的設置

讀取 /etc/profile.d 目錄下的腳本

運行 $HOME/.bash_profile (用戶環境變量文件)

運行 $HOME/.bashrc

運行 /etc/bashrc

1.5 特殊變量#

特殊參數變量

shell 的特殊變量,用在如腳本,函數傳遞參數使用,有如下特殊的,位置參數變量

$0	獲取 shell 腳本文件名,以及腳本路徑
$n	獲取 shell 腳本的第 n 個參數,n 在 1~9 之間,如 $1, $2$9 ,大於 9 則需要寫,${10},參數空格隔開
$#	獲取執行的 shell 腳本後面的參數總個數
$*	獲取 shell 腳本所有參數,不加引號等同於 $@ 作用,加上引號 "$*" 作用是接收所有參數為單個字符串,"$1 $2...."
$@	不加引號,效果同上,加引號,是接收所有參數為獨立字符串,如 "$1” “$2” “$3” ..., 空格保留

for_variables.sh

#! /bin/bash

for var in "$*"
do
	echo "$var"
done

for var in "$@"
	echo "$var"
done


bash for_variables.sh test ha 1 2 3 4 

特殊狀態變量

$?	上一次命令執行狀態返回值,0 正確,非 0 失敗
$$	當前 shell 腳本的進程號
$!	上一次後台進程的 PID
$_	再次之前執行的命令,最後一個參數

man bash  搜索 Special Parameters
echo
-n	不換行輸出
-e	解析字符串中的特殊字符

\n 換行
\r 回車
\t 制表
\b 退格

printf
eval
執行多個命令
eval ls;cd /tmp
exec
不創建子進程,執行後續命令,執行完畢後,自動 exit
expr
expr 函數名

1.6 shell 子串#

${變量}				返回變量值
${#變量}				返回變量長度,字符長度
${變量:Offset}		返回變量 Offset 數值之後的字符
${變量:Offset:length}	提取 Offset 之後的 length 限制的字符

# 刪除
${變量#word}			從變量開頭,刪除最短匹配的 word 子串
${變量##word}			從變量開頭,刪除最長匹配的 word
${變量%word}			從變量結尾刪除最短的 word
${變量%%word}			從變量結尾開始刪除最長匹配的 word

# 替換
${變量/pattern/string}用 string 代替第一個匹配的 pattern
${變量//pattern/string}用 string 代替所有的 pattern


# #指定字符內容截取
a*c 匹配開頭為 a,中間任意個字符,結尾為 c 的字符串 (大小寫敏感)
seq -s ":" 10
time for n in {1...10000};do char=`seq -s "testtt" 100`;echo ${#char} &>/dev/null;done

time for n in {1...10000};do char=`seq -s "testtt" 100`;echo ${char}|wc -L &>/dev/null;done

time for n in {1...10000};do char=`seq -s "testtt" 100`;expr length "${char}" &>/dev/null;done

time for n in {1...10000};do char=`seq -s "testtt" 100`;echo ${char}|awk "{print length($0)}" &>/dev/null;done

shell 編程,儘量使用 Linux 內置的命令,內置的操作,和內置的函數,效率最高

儘可能的減少管道符的操作

批量修改文件名

for file_name in `ls *.jpg`;do mv $file_name `echo ${file_name//_finished/}` done;

1.7 shell 擴展變量#

${parameter:-word}	如果 parameter 變量值為空,返回 word 字符串

${parameter:=word}	如果 parameter 變量為空,則 word 替代變量值,且返回其值

${parameter:?word}	如果 parameter 變量為空,word 當作 stderr 輸出,否則輸出變量值。用於設置變量為空導致錯誤時,返回的錯誤信息

${parameter:+word}	如果 parameter 變量為空,什麼都不做,否則 word 返回

stdout 1

stderr 2

應用:數據備份,刪除過期數據

find xargs
# 刪除 7 天以上過期數據
find path -name "" -type "文件類型" -mtime +7 | xargs rm -f

dir_path="/data/my_data"
find ${dir_path} -name '*.tar.gz' -type f -mtime +7 | xargs rm -f

find ${dir_path:=/data/my_data} -name '*.tar.gz' -type f -mtime +7 | xargs rm -f

1.8 父子 shell#

父子 shell_1
父子 shell_1

pstree

ps -ef
-e 列出所有進程的信息,如同 -A 選項
-f 顯示 UID,PID,PPID

ps -ef --forest

父子 shell_2
父子 shell_2

創建進程列表 (創建子 shell)

# shell 進程列表
(cd ~; pwd; ls; cd /tmp; ls)

檢測是否在子 shell 環境中

# 如果是 0,就是在當前 shell 環境中執行的,否則就是開辟子 shell 去運行的
echo $BASH_SUBSHELL

(cd ~; echo $BASH_SUBSHELL)

子 shell 嵌套

(pwd; echo $BASH_SUBSHELL)

(pwd; (echo $BASH_SUBSHELL))

利用括號,開啟子 shell 的理念,在 shell 腳本開發中,經常會用子 shell 進行多進程的處理提高程序並發執行效率

1.9 內置命令、外置命令#

內置命令:在系統啟動時就加載入內存,常駐內存,執行效率更高,但是佔用資源

外置命令:使用者需要從硬碟中讀取程序文件,再讀入內存加載

type cd

type ls

外置命令 特點:一定會開啟子進程執行

ps -f --forest

內置命令是 shell 的一部分,不需要單獨去某個文件,系統啟動後,便被加載到內存中

# 查看所有內置命令
compgen -b

總結#

echo "username: ${USER}"
echo "UID: $UID"
echo "User home: " $HOME
${}		取出變量值
$()		在括號中執行命令,得到執行結果
``		同上
()		開啟子 shell,執行
$vars	取出變量值

二、shell 開發#

2.1 數學運算#

Shell 算術運算符

算術運算符說明 / 含義
+、-加法(或正號)、減法(或負號)
*、/、%乘法、除法、取餘(取模)
**幂運算
++、--自增和自減,可以放在變量的前面也可以放在變量的後面
!、&&、||邏輯非(取反)、邏輯與(and)、邏輯或(or)
<、<=、>、>=比較符號(小於、小於等於、大於、大於等於)
==、!=、=比較符號(相等、不相等;對於字符串,= 也可以表示相當於)
<<、>>向左移位、向右移位
~、|、 &、^按位取反、按位或、按位與、按位異或
=、+=、-=、*=、/=、%=賦值運算符,例如 a+=1 相當於 a=a+1,a-=1 相當於 a=a-1

Shell 中常用的六種數學計算方式

運算操作符 / 運算命令說明
(( ))用於整數運算,效率很高,推薦使用。語法層面
let用於整數運算,和 (()) 類似。
$[]用於整數運算,不如 (()) 靈活。
expr可用於整數運算,也可以處理字符串。比較麻煩,需要注意各種細節,不推薦使用。
bcLinux 下的一個計算器程序,可以處理整數和小數。Shell 本身只支持整數運算,想計算小數就得使用 bc 這個外部的計算器。
declare -i將變量定義為整數,然後再進行數學運算時就不會被當做字符串了。功能有限,僅支持最基本的數學運算(加減乘除和取餘),不支持邏輯運算、自增自減等,所以在實際開發中很少使用。

2.1.1 雙小括號#

$(())	# $ 符號必須
# .sh 腳本中可不寫 echo
a=10
b=2
echo $(($a - $b))
echo $(($a > $b))

2.1.2 運算腳本#

#! /bin/bash

print_usage() {
	echo "請輸入數字!!!"
	exit 1
}

read -p "請輸入第一個數字: " firstnum
if [ -n "`echo` $firstnum | sed 's/[0-9]//g'" ]
  then
    print_usage
fi 


if [ "${operator}" != "+" ] && [ "${operator}" != "-" ] && [ "${operator}" != "*" ] && [ "${operator}" != "/" ]
  then
    echo "只能輸入 +-*/"
    exit 2
fi


read -p "請輸入第二個數字: " secondnum
if [ -n "`echo` $secondnum | sed 's/[0-9]//g'" ]
  then
    print_usage
fi

echo "${firstnum}${operator}${secondnum} 結果是:$((${firstnum}${operator}${secondnum}))"

2.1.3 檢測 nginx 服務是否運行#

while true;
  do
    wget --timeout=${timeout} --tries=1 http://xxx.com/ -q -O /dev/null
    if [ $? -ne 0 ]
      then
        let fails+=1
      else
        let success+=1
     fi
     
     if [ $success -ge 1 ]
       then
         echo "正常"
         exit 0
     fi
     
     if [ ${fails} -ge 2 ];then
       echo "錯誤"
       exit 2
     fi
done
-ne		不等於
-ge		大於等於

vim 定位另一個括號,shift + %

2.1.4 expr#

expr 1 + 2

# 模式匹配
expr aa.png ":" ".*"

expr aa.png ":" ".p"

# 判斷 jpg 文件
expr bb.jpg ":" ".*\.jpg" # 6
expr bb.jpghhfff ":" ".*\.jpg" # 也能匹配成功 # 6

判斷文件名後綴是否合法

#!/bin/bash

if expr "$1" ":" ".*\.jpg" &> /dev/null
  then
  	echo "這是一個 jpg!"
else
  echo "不是 jpg!"
fi

找出長度不大於 2 的單詞

#!/bin/bash

for str1 in This is a str, you know?
	do
		if [ `expr length str1` -le 2 ]
			then
				echo $str1
	done

2.1.5 bc, awk, 中括號計算#

bc 交互式計算

計算 1~100 的和

echo {1..100} | tr " " "+" | bc

seq -s "+" 100 | bc

echo $((`seq -s "+" 100`)) # 效率最高

seq -s "+" 100 | xargs expr
echo "2.2 1.1" | awk '{print ($1 + $2)}'
num=5
res=$[num+4]
echo $res

res=$[num*4]
echo $res

2.2 shell 條件測試#

條件測試語法說明
test <測試表達式>利用 test 命令進行條件測試表達式的方法。test 命令和 <測試表達式> 之間至少有一個空格
[ <測試表達式> ]透過 [](單中括號) 進行條件測試表達式的方法,和 test 命令的用法相同,這是老男孩推薦的方法。[] 的邊界和內容之間至少有一個空格
[[ <測試表達式> ]]透過 [](雙中括號) 進行條件測試表達式的方法,是比 test 和 [] 更新的語法格式。[[]] 的邊界和內容之間至少有一個空格
((<測試表達式>))這是透過 (()) 進行條件測試表達式的方法,一般用於 if 語句裡。(()) 兩端不需要有空格

2.2.1 test 條件測試#

-e 判斷該文件是否存在,(普通文件,目錄),存在就為真(0),否則為假(1)
echo $?

結合 &&    ||  使用

文件類型

選 項作 用
-b filename判斷文件是否存在,並且是否為塊設備文件
-c filename判斷文件是否存在,並且是否為字符設備文件
-d filename判斷文件是否存在,並且是否為目錄文件(常用)
-e filename判斷文件是否存在(常用)
-f filename判斷文件是否存在,並且是否為普通文件(常用)
-L filename判斷文件是否存在,並且是否為符號鏈接文件
-p filename判斷文件是否存在,並且是否為管道文件
-s filename判斷文件是否存在,並且是否為非空
-S filename判斷該文件是否存在,並且是否為套接字文件

文件權限判斷

選 項作 用
-r filename判斷文件是否存在,並且是否擁有讀權限
-w filename判斷文件是否存在,並且是否擁有寫權限
-x filename判斷文件是否存在,並且是否擁有執行權限
-u filename判斷文件是否存在,並且是否擁有 SUID 權限
-g filename判斷文件是否存在,並且是否擁有 SGID 權限
-k filename判斷該文件是否存在,並且是否擁有 SBIT 權限

文件比較

選 項作 用
filename1 -nt filename2判斷 filename1 的修改時間是否比 filename2 的新
filename -ot filename2判斷 filename1 的修改時間是否比 filename2 的舊
filename1 -ef filename2判斷 filename1 是否和 filename2 的 inode 号一致,可以理解為兩個文件是否為同一個文件。這個判斷用於判斷硬鏈接是很好的方法
-z 字符串為空就為真,否則為假
-n 反過來的,字符串是有內容就為真,否則為假

2.2.2 [ ] 條件測試#

test 和 [] 的作用一樣

[ ] 中前後有 空格

條件測試中使用變量,必須使用雙引號 ""

[ -f "${file1}" ]
[[ -f "${file1}" ]]

2.2.3 變量測試#

使用雙引號

2.2.4 字符串比較測試#

常用字符串測試操作符說明
-n "字符串"若字符串的長度不為 0,則為真。n 可以理解為 no zero
-z "字符串"若字符串的長度為 0,則為真。z 可以理解為 zero 的縮寫
"串 1" = "串 2"若字符串 1 等於字符串 2,則為真。可使用 "=="代替"="
"串 1" != "串 2"若字符串 1 不等於字符串 2,則為真。但不能用 !== 代替 "!="

變量要有雙引號

= 兩邊要有空格

2.2.5 數值比較測試#

在 [] 和 test 中使用在 (()) 和 [[]] 中使用的比較符號說明
-eq== 或 =相等 (equeal)
-ne!=不等 (not equal)
-gt>大於 (greater than)
-lt<小於 (less than)
-ge>=大於等於 (greater than or equal)
-le<=大於小於 (less than or equal)
-a&&and
-o||or
!!

一般使用 []

[[]] 也支持 -eq 等

2.2.6 邏輯運算#

read -p "請輸入一個字符:" var1

[ "$var1" -eq "1" ] && {
	echo $var1
	exit 0
}

[ "$var2" = "2" ] && {
	echo $var1
	exit 0
}

[ "$var1" != "2" -a "$var1" != "1" ] && {
	echo "請輸入 1 或 2!!"
	exit 1
}
# 正則表達式
[[ $num =~ [1-3] ]]

總結#

邏輯與 -a

邏輯或 -o

[[]] 無法使用 >=<= ,只能使用 -ge-le

測試表達式符號[]test[[]](())
邊界為是否需要空格需要需要不需要需要
邏輯操作符!, -a, -o!, -a, -o!, &&, ||!, &&, ||
整數比較操作符-eq, -gt, -lt, -ge, -le-eq, -gt, -lt, -ge, -le 或 =, >, <,>=, <=-eq, -gt, -lt, -ge, -le 或 =, >, <,>=, <==, >, <, >=, <=
字符串比較操作符=, ==, !==, ==, !==, ==, !==, ==, !=
是否支持通配符匹配不支持不支持支持不支持

最常用 []

2.3 腳本開發#

開發內存檢測腳本#

# 第二行,最後一個值
free -m | awk 'NR==2 {print $NF}'
#! /bin/bash
FreeMem=`free -m | awk 'NR==2 {print $NF}'`
CHARS="當前內存是 $FreeMem"

if [ "$FreeMem" -lt "100" ]; then
	echo $CHARS|tee /tmp/message.txt
	# mail -s 標題,收件人 < 內容
	mail -s "`date +%F-%T`$CHARS" [email protected] < /tmp/message.txt
fi

mysql 監控腳本#

mysql 監控腳本流程
mysql 監控腳本流程

# 本地
netstat -tunlp | grep mysql | wc -l
ss -tunlp | grep mysql | wc -l
lsof -i tcp:3380 | wc -l
# 遠程
nmap 127.0.0.1 -p 3380 | grep open | wc -l

# telnet
echo -e "\n" | telnet 127.0.0.1 3380 2>/dev/null | grep Connected | wc -l

Rsync 啟停腳本開發#

2.4 函數#

function xx() {

}

function xx{

}

xx(){

}

美化相關

lsb_functions="/lib/lsb/init-functions"
if test -f $lsb_functions;then
	. $lsb_functions
else
	init_functions="/etc/init.d/functions"
	if test -f $init_functions;then
		. $init_functions
	fi
	log_success_msg() {
		echo " 成功! $@"
	}
	log_failure_msg() {
		echo " 錯誤! $@"
	}
fi


log_success_msg echo "test"

函數返回值#

shell 的函數只能返回 整數值,如果想讓函數返回字符串,一般有兩種方法:將返回值賦值給一個字符串變量、輸出返回值,在函數調用處使用變量賦值。

https://www.cnblogs.com/duanxz/p/4661767.html

https://roc-wong.github.io/blog/2017/03/shell-%E5%87%86%E5%92%8C%E5%8F%8A%E5%8F%8A%E6%9C%89%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A%E5%8F%8A`

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。