第 9 堂課:正規表示法與 shell script 初探
http://linux.vbird.org/linux_basic_train/unit09.php
9.1:正規表示法的應用
9.1.1:grep 指令的應用
輸入 df 後,將 tmpfs 相關的那幾行取消,讓螢幕僅輸出一般的檔案系統,方便查閱。 (註:man grep 找 invert "反向" 搜尋的關鍵字)
[root@mail ~]# df | grep -v tmpfs
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/mapper/centos-root 14034944 1573508 12461436 12% /
/dev/sda1 1038336 190292 848044 19% /boot
9.1.2:正規表示法的符號意義
找出 /etc/services 內含 http 關鍵字的那幾行
[root@mail ~]# grep -n http /etc/services
承上,若僅須『開頭含有 http 』字樣的那幾行?
[root@mail ~]# grep -n ^http /etc/services
承上,若僅須『開頭含有 http 或 https 』字樣的那幾行?
[root@mail ~]# grep -n ^https* /etc/services
承上,若僅須『開頭含有 http 或 https 』字樣之外,且後面僅能接空白字元或 [tab] 字元的那幾行?
[root@mail ~]# grep -n ^https*[[:space:]] /etc/services
承上,若僅須『開頭含有 http 且後續接有 80 』字樣的那幾行
[root@mail ~]# grep -n ^https*[[:space:]]*80 /etc/services
找出 /etc/services 內含有星號 (*) 的那幾行
[root@mail ~]# grep -n \* /etc/services
找出 /etc/services 內含有星號,且星號前為英文(不論大小寫)的那幾行
[root@mail ~]# grep -n [[:alpha:]][\*] /etc/services
找出 /etc/services 含有一個數字緊鄰一個大寫字元的那幾行
[root@mail ~]# grep -n [[:digit:]][[:upper:]] /etc/services
找出 /etc/services 開頭是一個數字緊鄰一個大寫字元的那幾行
[root@mail ~]# grep -n ^[[:digit:]][[:upper:]] /etc/services
使用 find /etc 找出檔名,並找出結尾含有『 .conf 』的檔名資料
[root@mail ~]# grep -n .conf$ /etc/services
承上,且含有『大寫字元或數字』檔名在內的那幾個
[root@mail ~]# grep -n .conf$ /etc/services | grep [[:upper:]] | grep [[:digit:]]
9.1.3:sed 工具的使用
找出 /etc/passwd 裡面,結尾是 bash 的那幾行
[root@mail ~]# grep bash$ /etc/passwd
承上,透過 sed 將 /bin/bash 改成 /sbin/nologin 顯示到螢幕上
[root@mail ~]# grep bash$ /etc/passwd | sed 's/\/bin\/bash/\/sbin\/nologin/g'
承上,透過 tr 這個指令,將全部的英文都變成大寫字元
[root@mail ~]# grep bash$ /etc/passwd | tr '[:lower:]' '[:upper:]'
9.2.1:基礎 shell script 的撰寫與執行
如何直接以 bash 或 sh 去執行這隻腳本 (指的是直接用 bash 指令去執行,而不是執行 myid.sh)?
sh myid.sh
承上,執行過程中,如果還需要輸出程式碼之後才執行,可以加上哪個選項?(此功能相當有用!可用以檢測程式碼的錯誤, debug)
看不懂這題
若需要直接輸入 myid.sh 就能執行時,需要有什麼設定 (包括權限、路徑等等的資料) ?
myid.sh所在的目錄要在PATH裡面
myid要有x權限
如何使用絕對路徑來執行?
/home/student/bin/myid.sh
若你剛好在工作目錄下看到這個腳本,但你不確定工作目錄有沒有在 PATH 環境中,該如何下達指令執行該腳本?
直接sh ./myid.sh 或是 myid.sh
為何 alias 的結果沒有輸出?若執行該腳本時還要輸出目前的 alias ,該如何執行?為什麼?
要用source myid.sh
目前不知道為什麼...只知道source是用主線程執行,sh是用子線程執行,但為何主線程跟子線程執行結過有差異,目前還是想不通
9.2.2:shell script 的執行環境
例題:你在操作 Linux 系統的過程中,可能會切換到許多不同的 shell (例如 bash 轉到 csh 等等)。不過這些操作環境中,均需要使用到底下的變數, 且這些變數是在有需要時才載入的 (不是寫入到 .bashrc),因此需要額外撰寫成 myenv.sh。內容需要:
- 設計 MYIP 的變數為目前系統的 IP (假設網路卡為 eth0 時)
- 設計 mywork 的變數為指定到 /usr/local/libexec 目錄中
- 設計 megacli 的變數為 /opt/mega/cli/command 這個指令(此指令並不存在,僅作為範例用)
- 設計完畢之後,若要使用這個檔案內的資料,該如何執行?
#1 2 3
---------------------------------------------------------
MYIP=$(ip addr show | grep "inet\b" | awk '{print $2}')
mywork=/usr/local/libexec
megacli=/opt/mega/cli/command
#4
chmod a+x myenv.sh
myenv.sh
9.2.3:以對談式腳本及外帶參數計算 pi
例題:建立一個名為 /usr/local/bin/listcmd.sh 的腳本,該腳本可以完成底下的各項工作:
- 第一行一定要宣告 shell
- 顯示出這個腳本的目的 (中英文均可,例如: This shell script will list your command's full path name and permissions.)
- 開始透過 read 讓用戶輸入指令名稱
- 透過上一步驟取得指令名稱後,透過 which 找到這個指令的完整路徑
- 利用 ls -l 列出這個指令的完整權限
- 利用 getfacl 列出這個指令的完整權限
- 離開 shell script,並回傳 0 的數值。
最後將該指令的權限修訂成全部成員均可執行,並執行一次確認狀態。
vim listcmd.sh
---------------------------------------------------------------------------------
#!/bin/bash
echo -e "This shell script will list your command's full path name and permissions."
read -p "Please Input Command: " command
ls -l $(which ${command})
getfacl $(which ${command})
exit 0;
---------------------------------------------------------------------------------
chmod a+x listcmd.sh
例題:建立一個名為 /usr/local/bin/listcmd2.sh 的腳本,該腳本可以完成底下的各項工作:
- 第一行一定要宣告 shell
- 顯示出這個腳本的目的 (中英文均可,例如: This shell script will list your command's full path name and permissions.)
- 取得第一個外帶參數的內容
- 透過上一步驟取得指令名稱後,透過 which 找到這個指令的完整路徑
- 利用 ls -l 列出這個指令的完整權限
- 利用 getfacl 列出這個指令的完整權限
- 離開 shell script,並回傳 0 的數值。
最後將該指令的權限修訂成全部成員均可執行,並執行一次確認狀態。
cp listcmd.sh listcmd2.sh
------------------------------------------------------------------------------------
#!/bin/bash
echo -e "This shell script will list your command's full path name and permissions."
ls -l $(which ${1})
getfacl $(which ${1})
exit 0;
------------------------------------------------------------------------------------
9.2.4:透過 if .. then 設計條件判斷
請透過相同的方法來修改 mypi2.sh ,讓該腳本也能夠防呆。
#!/bin/bash
# Program:
# User input a scale number to calculate pi number.
# History:
# 2015/07/16 VBird First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
num=${1}
if [ "${num}" == "" ]; then # check empty number
echo "You must input a number..."
echo "I will use this number '20' to calculate pi"
num=20
else
checking="$(echo ${num} | grep '[^0-9]')" # check if any non-number char
if [ "${checking}" != "" ]; then # check non-number value
echo "You must input number..."
echo "I will use this number '20' to calculate pi"
num=20
fi
fi
if [ "${num}" -lt 10 ]; then
echo "I will use this number '10' to calculate pi"
num=10
elif [ "${num}" -gt 10000 ]; then
echo "I will use this number '10000' to calculate pi"
num=10000
fi
echo -e "This program will calculate pi value. \n"
echo -e "Starting calculate pi value. Be patient."
time echo "scale=${num}; 4*a(1)" | bc -lq
9.2.5:以 case .. esac 設計條件判斷
透過 case ... esac 的方法,修改 mypi2.sh 變成 mypi4.sh,以外帶參數的方式,讓 mypi4.sh 只能支援 20|100|1000 的數值, 若使用者外帶參數不是這三個,則顯示『 Usage: mypi4.sh 20|100|1000 』的螢幕提示,否則就直接計算 pi 值並輸出結果。
cp mypi2.sh mypi4.sh
vim mypi4.sh
-----------------------------------------
#!/bin/bash
# Program:
# User input a scale number to calculate pi number.
# History:
# 2015/07/16 VBird First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
num=${1}
case ${num} in
"20")
echo "Your input is 20"
;;
"100")
echo "Your input is 100"
;;
"1000")
echo "Your input is 1000"
;;
*)
echo "You MUST input 20|100|1000"
echo "I stop here"
exit 0
;;
esac
echo -e "This program will calculate pi value. \n"
echo -e "Starting calculate pi value. Be patient."
time echo "scale=${num}; 4*a(1)" | bc -lq
-----------------------------------------------
mypi4.sh 300
-----------------------------------------------
You MUST input 20|100|1000
I stop here
mypi4.sh 20
-----------------------------------------------
Your input is 20
This program will calculate pi value.
Starting calculate pi value. Be patient.
3.14159265358979323844
real 0m0.002s
user 0m0.000s
sys 0m0.000s
9.3:課後練習操作
分析『本日』登錄檔資訊的相關設定,重點在實做與練習正規表示法:(將答案寫入 /root/ans09.txt 中)
- 先解析一下 /var/log/messages 的內容中,每條訊息的最前面紀錄的日期,如何使用 date 搭配選項來輸出一樣的字串?(你或許需要知道搭配語系輸出)
- 設定一個變數名稱為 logday ,讓 logday 的內容為剛剛查詢到的日期格式
- 如何透過 grep 搭配 ${logday} 等方式,將 /var/log/messages 的資訊中,跟今天有關的日期取出來到螢幕上查閱?(注意日期要出現在行首喔!)
- 承上,上述的輸出結果中,我不想要關鍵字 dbus-daemon 與 dbus[數字] 的內容又該如何處理?
- 我想要透過一串指令,直接將 /etc/selinux/config 檔案內,行首出現『SELINUX=??? 』的那一行(一整行喔)資料,強制替換成『SELINUX=enforcing』, 且直接修改該檔案,該如何處理?
- 我要把 /etc/hosts 內容全部轉成大寫字元後,轉存到 /dev/shm/upperhosts 檔案,指令該如何處理?
#1 2 3 4
Docker Centos沒有/var/log/messages檔案,不過猜測是要考grep跟正規表示法的複合搭配
#5
Docker Centos沒有/etc/selinux/config檔案,不過猜測要考grep跟sed指令的複合搭配
#6
cat /etc/hosts | tr '[:lower:]' '[:upper:]' > /dev/shm/upperhosts
建立一隻名為 /usr/local/bin/myprocess 的腳本,腳本內容主要為:
- 第一行一定要宣告 shell 為 bash 才行;
- 主要僅執行『 /bin/ps -Ao pid,user,cpu,tty,args 』
- 這隻腳本必須要讓所有人都可以執行才行!
vim /usr/local/bin/myprocess
-----------------------------------------
#!/bin/bash
/bin/ps -Ao pid,user,cpu,tty,args
-----------------------------------------
chmod a+x /usr/local/bin/myprocesscal
寫一隻名為 /usr/local/bin/mydate.sh 的腳本,執行後可以輸出如下的資料:
- 第一行一定要宣告 shell 才對!
- 以 西元年/月/日 顯示出目前的日期
- 以 小時:分鐘:秒鐘 顯示出目前的時間
- 輸出從 1970/01/01 到目前累計的秒數
- 列出這個月的月曆,且依據台灣的習慣,輸出時,以星期一為一週的開始。
- 這隻腳本必須要讓所有人都可以執行才行!
vim /usr/local/bin/mydate.sh
------------------------------------------------
#!/bin/bash
date +'%Y/%m/%d'
date +'%H/%M/%S'
date +'%s'
cal -m
------------------------------------------------
chmod a+x /usr/local/bin/mydate.sh
寫一隻 /usr/local/bin/listcmd.sh 的腳本,該腳本執行後,會告知底下相關的事宜:
- 腳本的執行方式為『 listcmd.sh passwd 』,其中 passwd 可以使用任何檔名來取代
- 第一行一定要宣告 shell
- 先顯示出這個腳本的目的 (中英文均可,例如: This shell script will list your command's full path name and permissions.)
- 判斷是否有外帶參數,若沒有外帶參數,請 (1)螢幕顯示『 Usage: ${0} cmd_name 』,(2)並以回傳值 2 離開程式
- 使用『 which ${1} 2> /dev/null 』的結果,判斷該字串是否為指令
- 若該字串為指令,則依序輸出:
- 輸出指令的完整路徑
- 用 ls -l 列出這個指令的完整權限
- 利用 getfacl 列出這個指令的完整權限
- 離開 shell script,並回傳 0 的數值。
- 若該字串不為指令,則使用 locate 後面加 /${1}$ 的正規表示法 (locate 要支援正規表示法,必須要輸入特定的選項 請自行 man locate 查到正確的選項支援),然後依據 locate 之後的回傳值處理後續工作
- 若回傳值 (為 0) 顯示該字串其實具有相同的檔名,則使用 ls -ld 將檔名全部列出,然後以回傳值 0 離開程式
- 若回傳值 (不為 0) 顯示該字串並不為檔名,則顯示找不到這個檔名,然後以回傳值 10 離開程式
#!/bin/bash
echo -e "This shell script will list your command's full path name and permissions."
command=${1}
if [ "${command}" == "" ]; then
echo -e "Usage:${0} cmd_name"
exit 2;
fi
commandPath=$(which $command 2> /dev/null)
commandStatus=$(echo $?)
if [ "${commandStatus}" == "0" ]; then
echo -e $commandPAth
ls -l $commandPath
getfacl $commandPath
exit 0;
else
locateResult=$(locate -r /${command}$)
locateStatus=$(echo $?)
if [ "${locateStatus}" == "0" ]; then
ls -ld ${locateResult}
exit 0;
else
echo -e "Can't find file"
exit 10;
fi
fi
寫一隻名為 /usr/local/bin/myheha 的腳本,這隻腳本的執行結果會這樣:
- 腳本內第一行一定要宣告 shell 為 bash
- 當執行 myheha hehe 時,螢幕會輸出『 I am haha 』
- 當執行 myheha haha 時,螢幕會輸出『 You are hehe 』
- 當外帶參數不是 hehe 也不是 haha 時,螢幕會輸出『 Usage: myheha hehe|haha 』
#!/bin/bash
case ${1} in
"hehe")
echo -e "I am haha"
;;
"haha")
echo -e "you are hehe"
;;
*)
echo -e "Usage:myheha hehe|haha"
;;
esac
寫一隻判斷生日的腳本,名稱為 /usr/local/bin/yourbday.sh,內容為:
- 腳本內第一行一定要宣告 shell 為 bash
- 指令執行的方式為『 yourbday.sh YYYY-MM-DD 』
- 當使用者沒有輸入外帶參數時,螢幕顯示『 Usage: yourbday.sh YYYY-MM-DD 』,並且離開程式
- 以正規表示法的方式來查詢生日的格式是否正常,若不正常,重新顯示上面的訊息,並且離開程式
- 以 date --date="YYYY-MM-DD" +%s 的回傳值確認時間格式是否正確?若不正確請顯示『 invalid date 』後,離開程式
- 分別取得生日與現在的累積秒數,根據兩者的差異,同時假設一年 365.25 天,然後:
- 如果生日比現在的總累積秒數還要大,代表來自未來,請輸出『You are not a real human..』,之後離開程式
- 如果所有問題都排除了,那請搭配 bc 來顯示出你的歲數,歲數計算到小數點第二位, 例如『 You are 22.35 years old 』的樣式。
#!/bin/bash
command1=${1}
echo $command1
if [ "$command1" == "" ]; then
echo -e "Usage: yourbday.sh YYYY-MM-DD";
exit 0;
fi
birthdayTime=$(date --date=$command1 +"%s")
dateResult=$(echo $?)
if [ "$dateResult" -ne "0" ]; then
echo "Invalid date"
exit 0;
fi
currentTime=$(date +"%s")
if [ $currentTime -gt $birthdayTime ]; then
echo "(${currentTime} - ${birthdayTime})/86400/365.24" | bc -lq
else
echo -e "Your are not a real human..."
fi
有一隻腳本名為: /usr/local/sbin/examcheck ,當執行時,應該要出現如下的畫面, 但是程式開發人員寫錯了某些地方,請你將應該有問題的程式碼訂正,使得腳本得以展示如下的結果:
- 執行 examcheck ok 時,顯示『Yes! You are right!』
- 執行 examcheck false 時,顯示『So sad... your answer is wrong..』
- 執行 examcheck otherword 時,顯示『 Usage: examcheck ok|false 』(otherword 為任意字元,隨便不是 ok 與 false 的其他字元之意)
#!/bin/bash
case ${1} in
"ok")
echo -e "Yes! You are right"
;;
"false")
echo -e "So sad... your answer is wrong..."
;;
*)
echo -e "Usage:examcheck ok|false"
;;
esac