- 以 #!解析器名稱 開頭,表示選擇哪個解釋器解釋shell腳本
- source命令
- export命令
- env命令
- unset命令
第二章 shell編程基礎 - 函數傳遞
- 標准輸入輸出符號
第三章 編程的基本元素 - 獲取命令執行返回值
- $((數值計算)) 獲取數值計算結果 如:$((100 - 2*100/400))
- 替換運算符
- 模式匹配運算符
- shift命令可以截取參數列表最左端的一個參數
- type命令判斷被執行命令的來源(別名、關鍵字、函數、內置命令、外部命令)
- test命令用於評估表達式,返回零(true)或者非零(false)
- 邏輯運算符
- 運算符號
- 執行反單引號(`)之間的命令,引用結果作為字符串
- getopt命令用於分析命令標志和參數
第四章 正則表達式 - 元字符
- POSIX字符集
- 后向引用
- 交替、分組
第五章 基本文本處理 - 排序文本
- 文本去重
- 統計文本
- 打印和格式化輸出
- 提取文本開頭和結尾
- 字段處理
- 文本替換
- Linux下的配置文件
第六章 文件和文件系統 - 文件
- 文件系統
第七章 流編輯器sed - 工作地址范圍
- 命令
- [:特殊字符:]用於匹配特俗字符
第八章 文本處理利器awk - awk代碼結構
- 內建變量
- 局部變量
- 字符串函數
第九章 進程 - 進程管理命令
- init進程
- 調度系統任務
- 加載proc虛擬文件系統:mount -t proc proc /proc
第十章 OpenSSH - 安裝openssh
- 使用SSH登錄遠程主機(要求遠程主機正在運行sshd)
第十一章 實用程序(日志處理程序、系統監控程序) - 日志清理程序
- 系統監控程序
第一個Shell程序
以 #!解析器名稱 開頭,表示選擇哪個解釋器解釋shell腳本
source命令
使用source執行shell腳本時,不會創建子進程,而在父進程中直接執行。
當需要在程序中修改當前shell本身的環境變量時,使用source命令
source命令也可用來讀入包含函數的文件
使用方法:source fileName 或者 . fileName
export命令
export命令用於設置或顯示環境變量
使用方法:export [-fnp] [變量名稱]=[變量設置值]
-f 代表[變量名稱]中為函數名稱
-n 刪除指定的變量。變量實際上並沒有刪除,只是不會輸出到后續指令的執行環境中
-p 列出所有的shell賦予程序
env命令
env命令用於臨時改變環境變量值
unset命令
從當前shell刪除變量或函數
shell編程基礎
函數傳遞
$0 $1 $2 位置參數
$* 以一個單字符串顯示所有向腳本傳遞的參數
$@ 所有向腳本傳遞的參數
$# 傳入函數的參數個數
$$ 腳本運行的當前進程id號
$! 后台運行的最后一個進程id號
$? 顯示最后命令的退出狀態
$- 顯示shell使用的當前選項
標准輸入輸出符號
0<:標准輸入
1> 或者 >:重定向標准輸出
2>:重定向標准錯誤
&>:標准輸出和標准錯誤
編程的基本元素
獲取命令執行返回值
- $(命令) 如:$(date +%Y%m%d%H%M%S)
命令
如:echo 123
$((數值計算)) 獲取數值計算結果 如:$((100 - 2*100/400))
替換運算符
- ${varname:-word}
如果varname存在且非null,則返回varname的值;否則,返回word - ${varname:=word}
如果varname存在且非null,則返回varname的值;否則,將varname的值設置為word,然后返回word - ${varname:?message}
如果varname存在且非null,則返回varname的值;否則打印message,並退出當前腳本 - ${varname:+word}
如果varname存在且非null,則返回word;否則返回null
模式匹配運算符
- ${varname#pattern}
如果模式匹配變量取值的開頭處,則刪除匹配的最短部分,並返回剩下部分 - ${varname##pattern}
如果模式匹配變量取值的開頭處,則刪除匹配的最長部分,並返回剩下部分 - ${varname%pattern}
如果模式匹配變量取值的結尾處,則刪除匹配的最短部分,並返回剩下部分 - ${varname%%pattern}
如果模式匹配變量取值的結尾處,則刪除匹配的最長部分,並返回剩下部分 - ${varname/pattern/string} ${varname//pattern/string}
將varname中匹配模式的最長部分替換為string
第一種格式中,只有匹配的第一部分被替換,第二種格式中,varname中所有匹配的部分都被替換
如果模式以#開頭,則必須匹配varname的開頭,如果模式以%開頭,則必須匹配varname的結尾
shift命令可以截取參數列表最左端的一個參數
type命令判斷被執行命令的來源(別名、關鍵字、函數、內置命令、外部命令)
test命令用於評估表達式,返回零(true)或者非零(false)
邏輯運算符
- 關於文件與目錄的偵測邏輯卷標!
-f 常用!偵測『文件』是否存在 eg: if [ -f filename ]
-d 常用!偵測『目錄』是否存在
-b 偵測是否為一個『 block 文件』
-c 偵測是否為一個『 character 文件』
-S 偵測是否為一個『 socket 標簽文件』
-L 偵測是否為一個『 symbolic link 的文件』
-e 偵測『某個東西』是否存在! - 關於程序的邏輯卷標!
-G 偵測是否由 GID 所執行的程序所擁有
-O 偵測是否由 UID 所執行的程序所擁有
-p 偵測是否為程序間傳送信息的 name pipe 或是 FIFO - 關於文件的屬性偵測!
-r 偵測是否為可讀的屬性
-w 偵測是否為可以寫入的屬性
-x 偵測是否為可執行的屬性
-s 偵測是否為『非空白文件』
-u 偵測是否具有『 SUID 』的屬性
-g 偵測是否具有『 SGID 』的屬性
-k 偵測是否具有『 sticky bit 』的屬性 - 兩個文件之間的判斷與比較 ;例如[ test file1 -nt file2 ]
-nt 第一個文件比第二個文件新
-ot 第一個文件比第二個文件舊
-ef 第一個文件與第二個文件為同一個文件( link 之類的文件) - 邏輯的『和(and)』『或(or)』
&& 邏輯的 AND 的意思
|| 邏輯的 OR 的意思
運算符號
= 等於 應用於:整型或字符串比較 如果在[] 中,只能是字符串
!= 不等於 應用於:整型或字符串比較 如果在[] 中,只能是字符串
< 小於 應用於:整型比較 在[] 中,不能使用 表示字符串
大於 應用於:整型比較 在[] 中,不能使用 表示字符串
-eq 等於 應用於:整型比較
-ne 不等於 應用於:整型比較
-lt 小於 應用於:整型比較
-gt 大於 應用於:整型比較
-le 小於或等於 應用於:整型比較
-ge 大於或等於 應用於:整型比較
-a 雙方都成立(and) 邏輯表達式 –a 邏輯表達式
-o 單方成立(or) 邏輯表達式 –o 邏輯表達式
-z 空字符串
-n 非空字符串
執行反單引號(`)之間的命令,引用結果作為字符串
getopt命令用於分析命令標志和參數
正則表達式
元字符
^ 鎖定行或字符串的開始
$ 鎖定行或字符串的結尾
當^和$結合使用時,意味着模式必須匹配整個串
. 匹配除了換行符以外的任意字符
[...] 方括號表達式,匹配括號內任意一個字符;如果^符號位於方括號的開始,則不匹配方括號中的任意字符
\ 轉義字符,用於打開或關閉后續字符的特殊含義
x{m,n} 區間表達式,匹配x字符出現的次數區間
? 匹配前面正則表達式的零個或一個實例
- 匹配前面正則表達式的一個或多個實例
- 匹配零個或多個前面字符
| 匹配前面或后面的正則表達式
() 匹配括號括起來的正則表達式
\b 單詞鎖定符,代表單詞的開頭和結尾,即單詞的分界處
\B 匹配兩個單詞組成字符間的空字符串
< > 分別匹配單詞開頭和單詞結尾
\n 換行符
\d 匹配一位數字
\w 匹配文字和數字字符
\W 匹配一個或多個非單詞字符
POSIX字符集
[:alnum:] 數字字符
[:alpha:] 字母字符
[:blank:] 空格與制表符
[:cntrl:] 控制字符
[:digit:] 數字字符
[:graph:] 非空格
[:lower:] 小寫字母
[:print:] 可顯示的字符
[:punct:] 標點符號字符
[:space:] 空白(whitespace)字符
[:upper:] 大寫字母
[:xdigit:] 十六進制數字
[. .] 排序符號,如[.cn.]表示cn字符序列,而單獨的c和n都不行
[= =] 等價字符集
后向引用:匹配之前正則表達式使用(和)括起來選定之后引用的模式,使用\1~\9來引用選定的模式
如:(go).*\1 匹配一行中前后出現兩個go
交替、分組
交替|:在不同序列之間用管道符號隔開
分組():讓元字符修飾前置字符串
如:(man|woman)+ 匹配一個或多個man或者woman字符串
基本文本處理
排序文本
sort命令用於排序文件,對已排序的文件進行合並,並檢查文件以確定它們是否已排序
文本去重
uniq命令用於文本去重(在使用uniq命令前,先使用sort命令,使所有重復行相鄰)
統計文本
wc命令用於統計文本行數、字數以及字符數
打印和格式化輸出
pr命令用於將文本轉換成適合打印的文件
fmt命令用於編排文本文件
fold命令限制文本寬度
提取文本開頭和結尾
head命令提取文件開頭
tail命令提取文件結尾
字段處理
cut命令用於從一個文本文件或者文本流中提取文本列
join命令用於根據指定欄位,找到兩個文件中指定欄位內容相同的行,將它們合並,並根據要求的格式輸出內容
文本替換
tr命令用於替換字符
Linux下的配置文件
/etc/group 用戶組定義
/etc/passwd 用戶信息定義
/etc/inittab init的配置文件,在Linux啟動時扮演重要角色
/etc/shadow 用戶密碼的存放地址
/etc/crontab cron(定期執行命令的程序)的配置文件
/etc/fstab 文件系統信息
文件和文件系統
文件
ls命令用於列出文件
chown命令用於改變文件的所有者
chgrp命令用於改變文件的用戶組
umask命令用於指定哪些權限在新文件的默認權限中被刪除
chmod命令用於修改文件權限
touch命令更新文件的訪問和修改時間
find命令用於尋找文件
xargs命令用於遍歷處理文件
comm命令用於比較兩個已排序文件之間的差異
diff命令用於比較兩個文件之間的差異
文件系統
fdisk命令用於查看/修改系統的分區表
mkfs命令用於創建文件系統
mount命令用於加載文件系統到指定的加載點
umount命令用於卸載已經加載的文件系統
df命令用於顯示當前掛載情況
流編輯器(sed)
工作地址范圍
- 行地址 如:刪除第一行 sed -e '1d' filePath
- 行范圍地址 如:打印1到5行 sed -n -e '1,5p' filePath
- 正則表達式地址 如:打印所有以開頭的注釋行 sed -n -e '/^#/p' filePath
- 兩個用逗號分開的正則表達式之間的地址 如:打印從包含'BEGIN'的行開始,並且包含'END'的行結束的文本塊 sed -n -e '/BEGIN/,/END/p' filePath
命令
- d 刪除
- p 打印
- s/// 替換
- = 打印行號
- i 插入
- a 追加
[:特殊字符:]用於匹配特俗字符
文本處理利器(awk)
awk代碼結構
- 處理輸入前的初始化
BEGIN{
....
} - 處理輸入過程
[ 條件 ] {
...
} - 處理完所有輸入后的掃尾工作
END{
...
}
內建變量
FILENAME 當前輸入文件的名稱
FS 字段分隔符(支持正則表達式),默認為空格
OFS 輸出字段分隔字符,默認為空格
ORS 輸出記錄分隔字符,默認為\n
RS 輸入記錄分隔字符
NF 當前記錄的字段數
NR 在工作中的記錄數
FNR 當前輸入文件的記錄數
局部變量:列在函數參數列表中並且在字首前置一些額外的空白 如: add(x,y, sum) {}
字符串函數
sub(/reg/, newsubstr, str) 只替換第一個匹配字符串
gsub(/reg/, newsubstr, str) 將字符串str中所有符號/reg/正則的子串替換為字符串newsubstr
index(str, substr) 返回子串substr在串str中的索引
length(str) 返回字符串的長度
match(str, /reg/) 如果在串str中找到正則/reg/匹配的串,則返回出現的位置,未找到則返回0
split(str, array, sep) 使用分隔符sep把字符串分解成數組array
substr(str, position[, length]) 返回str中從position開始的length個字符
toupper(str) 對字符進行大小寫轉換
sprintf("format", expr) 對expr使用printf格式說明
進程
進程管理命令
fork函數用於創建進程
ps命令用於查看系統正在運行的進程
top命令用於查看系統一段時間進程的動態信息
pstree命令用於打印進程樹形結構
Ctrl+C快捷鍵用於中斷前台進程
Ctrl+\快捷鍵用於殺死前台進程
Ctrl+Z快捷鍵用於掛起前台進程
bg命令用於將掛起進程轉換為后台進程
fg命令用於將后台進程轉換為前台進程
jobs命令用於顯示當前shell的進程狀況
kill命令用於向指定進程發送信號
init命令用於進程初始化工具,可切換運行等級
init進程
- /etc/inittab init程序讀取的配置文件
基本格式為 id:runlevels:action:process- id為1~2個字符,配置行的唯一標識,在配置文件中不能重復
- runlevels(運行等級)取值如下
- 等級0表示:表示關機(千萬不能把initdefault 設置為0)
- 等級1表示:單用戶模式
- 等級2表示:無網絡連接的多用戶命令行模式
- 等級3表示:有網絡連接的多用戶命令行模式
- 等級4表示:不可用
- 等級5表示:帶圖形界面的多用戶模式
- 等級6表示:重新啟動(千萬不要把initdefault 設置為6)
- action取值如下
- respawn 啟動並監視第4項指定的process,若process終止則重啟它
- wait 執行第4項指定的process,並等待它執行完畢
- once 執行第4項指定的process
- boot 不論在哪個執行等級,系統啟動時都會運行第4項指定的process
- bootwait 不論在哪個執行等級,系統啟動時都會運行第4項指定的process,且一直等它執行完備
- off 關閉任何動作,相當於忽略該配置行
- ondemand 進入ondemand執行等級時,執行第4項指定的process
- initdefault 系統啟動后進入的執行等級,該行不需要指定process
- sysinit 不論在哪個執行等級,系統會在執行boot 及bootwait之前執行第4項指定的process
- powerwait 當系統的供電不足時執行第4項指定的 process,且一直等它執行完畢
- powerokwait 當系統的供電恢復正常時執行第4項指定的process,且一直等它執行完畢
- powerfailnow 當系統的供電嚴重不足時執行第4項指定的process
- ctrlaltdel 用戶按下【Ctrl+Alt+Del】時執行的操作
- kbrequest 當用戶按下特殊的組合鍵時執行第4項指定的process,此組合鍵需在keymaps文件定義
- process為所要執行的shell命令。任何合法的shell語法均適用於該字段。
- /etc/rc.d/rcX.d文件(X代表運行等級)含有各個運行等級服務啟動和終止配置
/etc/rc.d/init.d目錄下存放着對應運行等級的服務腳本 - 修改配置/etc/inittab后馬上生效:kill -1 1 或者 init q
調度系統任務
- crontab命令用於調度重復性的任務
控制訪問的文件:cron.allow、cron.deny - at命令用於調度只執行一次的任務
控制訪問的文件:at.deny
加載proc虛擬文件系統:mount -t proc proc /proc
SSH
安裝openssh
-
替換阿里雲的源
echo "http://mirrors.aliyun.com/alpine/latest-stable/main/" > /etc/apk/repositories
echo "http://mirrors.aliyun.com/alpine/latest-stable/community/" >> /etc/apk/repositories -
同步時間
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime -
更新源、安裝openssh 並修改配置文件、生成key、啟動sshd服務
apk update &&
apk add --no-cache openssh-server tzdata &&
sed -i "s/#PermitRootLogin.*/PermitRootLogin yes/g" /etc/ssh/sshd_config &&
ssh-keygen -t rsa -P "" -f /etc/ssh/ssh_host_rsa_key &&
ssh-keygen -t ecdsa -P "" -f /etc/ssh/ssh_host_ecdsa_key &&
ssh-keygen -t ed25519 -P "" -f /etc/ssh/ssh_host_ed25519_key &&
/usr/sbin/sshd -D
使用SSH登錄遠程主機(要求遠程主機正在運行sshd)
-
基於口令的登錄方法
ssh -l 登錄賬號 遠程主機 -
基於密鑰對的登錄方法
- 生成密鑰對:ssh-keygen -d
- 把公鑰上傳到服務器上(/.ssh/id_dsa.pub、/.ssh/authorized_keys)
- 測試自動登錄:ssh [登錄賬號@]遠程主機 (需要輸入第一步輸入的passphrase,若想不輸入passphrase可以考慮ssh-agent)
實用程序
日志清理程序
把以下代碼保存為log_clean.sh文件中即可使用
內含操作:備份重要的日志、限制日志目錄大小、清理老舊日志
# maximum log size
alarmrate=500
# the max size file can reach
file_max_size=5
# this is the directory where fresh logs are originally written
working_dir=/mnt/soho_storage/log
# this is the frequency our program runs
SLEEPTIME=5
# append year.month.day and timestamp to log filename
filenameConvert()
{
timestamp=$(date +%Y%m%d%H%M%S)
timestamp=`echo $timestamp`
RETVAL=$1.$timestamp
}
# search dir to fetch the oldest log
searchdir()
{
oldestlog=`ls -rt | head -n 1 | awk '{print $1}'`
}
# this function clean old logs under working dir if it reaches it's size limitation
clear_old_log_under_working_dir()
{
cd $working_dir
while true
do
logsize=`du -ms $working_dir | awk '{print $1}'`
if [ $logsize -gt $alarmrate ]
then
searchdir
rm -rf $oldestlog
else
break;
fi
done
}
# this is the main process of our log backup activity
backuplog_process()
{
cd $log_ram_dir
for i in *
do
file_size=`du -m $i | awk '{print $1}'`
# need to backup log file
case $i in access.log | error.log | apcupsd.events | soho.log)
if [ ! -d $working_dir ]
then
mkdir -p $working_dir
fi
if [ file_size -gt file_max_size ]
then
filenameConvert $i
cp $log_ram_dir/$i $working_dir/$RETVAL
echo "" > $log_ram_dir/$i
clear_old_log_under_working_dir
fi
;;
*)
if [ file_size -gt file_max_size ]
then
echo "" > $log_ram_dir/$i
fi
done
}
while true
do
backuplog_process
sleep $SLEEPTIME
done
系統監控程序
把以下代碼保存為system_monitor.sh文件中即可使用
內含操作:監控內存、硬盤、CPU、進程,形成狀態報告
# maximum ratio of memory usage
mem_quota=80
# hard disk
hd_path=/dev/sda1
# maximum ratio of hard disk usage
hd_quota=80
# maximum ratio of cpu usage
cpu_quota=80
# time gap between two times fetching cpu status
time_gap=60
# generate report every 10 minutes
runtime_gap=60
# fetch the ratio of memory usage
# @return 1: if larger than $mem_quota
0: if less than $mem_quota
watch_memory()
{
mem_total=`cat /proc/meminfo | grep MemTotal | awk '{print $2}'`
mem_free=`cat /proc/meminfo | grep MemFree | awk '{print $2}'`
mem_usage=$((100-mem_free*100/mem_total))
if [ $mem_usage -gt $mem_quota ]
then
mem_message="ALARM!! The memory usage is $mem_usage%!!"
return 1
else
return 0
fi
}
# fetch the top 10 most wasting memory process
proc_memory_top10()
{
mem_busiest=`ps aux | sort -nk 4r | head -n 11`
}
# fetch the ratio of hard disk usage
# @return 1: if larger than $hd_quota
0: if less than $hd_quota
watch_hd()
{
hd_usage=`df | grep $hd_path | awk '{print $5}' | sed 's/%//g'`
if [ $hd_usage -gt $hd_quota ]
then
hd_message="ALARM!! The hard disk usage is $hd_usage%!!"
return 1
else
return 0
fi
}
# fetch cpu status at a time point
# format used unused
get_cpu_info()
{
cat /proc/stat | grep -i "^cpu[0-9]\+" | awk '{used+=$2+$3+$4;unused+=$5+$6+$7+$8} END{print used,unused}'
}
# fetch the ratio of cpu usage
# fetch cpu stat two times, with time gap, then calculate the average status
# @return 1: if larger than $cpu_quota
0: if less than $cpu_quota
watch_cpu()
{
time_point_1=`get_cpu_info`
sleep $time_gap
time_point_2=`get_cpu_info`
cpu_usage=`echo $time_point_1 $time_point_2 | awk '{used=$3-$1;total+=$3+$4-$2-$1}';print $used*100/total`
if [ $cpu_usage -gt $cpu_quota ]
then
cpu_message="ALARM!! The cpu usage is over $cpu_usage%!!"
return 1
else
return 0
fi
}
# fetch the top 10 busiest processes
proc_cpu_top10()
{
proc_busiest=`ps aux | sort -nk 3r | head -n 11`
}
while true
do
# report content
report=""
# memory monitor
if [ `watch_memory` -eq 1 ]
then
report=$report'\n'$mem_message
proc_memory_top10
report=$report'\n'$mem_busiest
fi
# hard disk monitor
if [ `watch_hd` -eq 1 ]
then
report=$report'\n'$hd_message
fi
# cpu monitor
if [ `watch_cpu` -eq 1 ]
then
report=$report'\n'$cpu_message
proc_cpu_top10
report=$report'\n'$proc_busiest
fi
# feedback report
if [ -n $report ]
then
# todo...
fi
# sleep time
sleep $((runtime_gap-time_gap))
done