什么是Shell
shell 是命令解釋器,用于解釋用戶對操作系統(tǒng)的操作。
shell有很多
cat /etc/shells
CentOS 7 默認使用的shell是bash
UNIX的哲學:一條命令只做一件事情
為了組合命令和多次執(zhí)行命令,使用腳本文件來保存需要執(zhí)行的命令
賦予該文件執(zhí)行權限(chmod u+rx filename)
Shell腳本
Sha-Bang
命令
“#”號開頭的注釋
chmod u+x filename 可執(zhí)行權限
執(zhí)行命令
bash ./filename.sh 會生成一個子進程(不需要執(zhí)行權限)
./filename.sh 會生成一個子進程,使用Sha-Bang (需要可執(zhí)行權限)
source ./filename.sh 在當前進程運行
. filename.sh (點之后會產(chǎn)生一個子進程)
比如一個腳本如下:
#! /bin/bash
cd /tmp
在/home目錄下運行
bash ./filename.sh 運行,子進程運行cd,然后子進程結束,此時pwd,還是在 /home 而不是/tmp
source ./filename.sh 或者 . filename.sh,這兩個在/tmp,不產(chǎn)生子進程
內(nèi)建命令和外部命令的區(qū)別
內(nèi)建命令不需要創(chuàng)建子進程,內(nèi)建命令比如source
內(nèi)建命令對當前shell生效
管道和重定向
Shell管道是Shell中最值得稱贊的功能之一,它以非常簡潔的形式實現(xiàn)了管道的進程間通信方式,我個人認為Shell處理文本數(shù)據(jù)的半壁江山都來自于豎線形式的管道。像其它編程語言,打開管道后還要區(qū)分哪個進程寫管道、哪個進程讀管道,為了安全,每個進程還要關閉不用的讀端或寫端,總之就是麻煩,而Shell的管道非常簡潔,豎線左邊的就是寫管道的,豎線右邊的就是讀管道的。
管道和信號一樣,也是進程通信的方式之一
匿名管道(管道符)是 Shell 變成經(jīng)常用到的通信工具
管道符是“|”,將前一個命令執(zhí)行的結果傳遞給后面的命令
ps | cat
ps aux | grep 'sshd'
echo 123 | psecho 123 |cat |cmd 可以連續(xù)使用
注意一下輸出重定向符
一個進程默認會打開標準輸入、標準輸出、錯誤輸出三個文件描述符
輸入重定向符號 “<”
read var < /path/to/a/file
read var1 < a.txt
輸出重定向符號 ">" ">>" "2>" "&>"
echo 123 > /path/to/a/file 清空再輸入
echo 123 >> /path/to/a/file 追加
2> 命令執(zhí)行過程中有錯誤則重定向
&> 命令執(zhí)行過程中無論正確錯誤都重定向
輸入和輸出重定向組合使用
cat > /path/to/a/file.sh << EOF
i am $USER
EOF
運行以上三句話,會生成一個file.sh文件,文件里內(nèi)容為i am $USER
變量
變量的賦值
變量名的命名規(guī)則
字母、數(shù)字、下劃線
不以數(shù)字開頭
變量的賦值
為變量賦值的過程中,稱為變量替換
變量名=變量值
a=123 (不允許出現(xiàn)空格,shell會認為前面不是變量名而是一個命令,比如reboot =1),會重啟
使用let為變量賦值
let a=10+20 (盡量少用,效率很低)
將命令賦值給變量
l=ls (用處不大)
將命令結果賦值給變量,使用$() 或者 ''
letc=$(ls -l /etc)
letc='ls /root'
變量值有空格等特殊字符可以包含在 "" 或 '' 中
srring1='hello bash'
string2="hello I'm name"
變量引用和作用范圍
變量的引用
${變量名}稱作對變量的引用
echo ${變量名} 查看變量的值
${變量名} 在部分情況下可以省略為 $變量名
變量的作用范圍
變量的默認作用范圍
當前的shell,父進程的變量對子進程無效,子進程的對父進程也無效。
可以使用source
變量的導出
export ,子進程可以獲得父進程的變量
export demo_var1="hello subshell"
變量的刪除
unset
unset demo_var1
系統(tǒng)環(huán)境變量,預定義變量,位置變量
環(huán)境變量:每個Shell打開都可以獲得到的變量
set 和 env 命令
env | more 查看當前所有的環(huán)境變量
echo ${HOME} 查看單個環(huán)境變量
$PATH 當前命令的搜索路徑
所以要在$PATH 中新增路徑,使用PATH=$PATH:新加路徑(只對當前終端生效,對子shell生效)
$PS1 當前提示終端
預定義變量
echo $? $$ $0等
$? 指上一條命令是否正確執(zhí)行,echo $?,正確執(zhí)行返回0,錯誤1
$$ 顯示當前進程 PID
$0 顯示當前進程名稱
位置變量
$1 $2 ... ${10},需要有{}
比如有腳本 test.sh]如下:
#! /bin/bash
pos1=$1
pos2=$2
echo $pos1
echo $pos2
執(zhí)行的時候,./test.sh -a -l
會傳參進去,可以對腳本進行簡化
echo $1
echo $2
考慮到echo $2 的時候 $2 有可能是空值。所以寫成下面這樣
pos1=$1
pos2=${2}_
echo $pos1
echo $pos2
如果沒有傳參,則$2默認為_,規(guī)避讀入的值是空值。但是這么寫,如果傳參進去,后面會多一個_,所以可以改成下面這樣:
pos2=${2-_}
常見的環(huán)境變量
HOSTNAME=control_node
USER=root
HOME=/root
SHELL=/bin/bash
HISTSIZE=1000
SSH_TTY=/dev/pts/2
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
MAIL=/var/spool/mail/root
PWD=/root
LANG=en_US.UTF-8
常見的特殊變量
$1,$2,...,$N:腳本的位置參數(shù)
$0:shell或shell腳本的名稱
$*:擴展為位置參數(shù),"$*"會將所有位置參數(shù)一次性包圍引起來,"$*"等價于"$1_$2_$3..."
$@:擴展為位置參數(shù),"$@"會將每個位置參數(shù)單獨引起來,"$@"等價于"$1" "$2" "$3"...
$#:位置參數(shù)的個數(shù)
$$:當前Shell的進程PID,在某些子Shell(如小括號()開啟的子Shell)下,會被繼承。如果可以,建議使用$BASHPID替代$$
$?:最近一個前臺命令的退出狀態(tài)碼
$!:最近一個后臺命令的進程PID
$-:當前Shell環(huán)境的一些特殊設置,比如是否交互式
$_:最近一個前臺命令的最后一個參數(shù)(還有其它情況,該變量用的不多,所以不追究了)
需要注意一下的??
關于$* "$*" $@ "$@"的區(qū)別,參見如下shell腳本測試:
#!/bin/bash
echo '$*----------':
for i in $*;do echo "<$i>";done
echo '"$*--------"':
for i in "$*";do echo "<$i>";done
echo '$@----------':
for i in $@;do echo "<$i>";done
echo '"$@--------"':
for i in "$@";do echo "<$i>";done
$ chmod +x position_parameters.sh
$ ./position_parameters.sh a b 'c d'
$*---------:
<a>
<b>
<c>
<d>
"$*--------":
<a b c d>
$@----------:
<a>
<b>
<c>
<d>
"$@--------":
<a>
<b>
<c d>
環(huán)境變量配置文件
配置文件
/etc/profile
/etc/profile.d/
~/.bash_profile
~/.bashrc
/etc/bashrc
所以經(jīng)常在 /etc/profile 中新增 export PATH=$PATH:/new/path
su - 切換用戶會加載4個文件
su 切換用戶只會加載~/.bashrc、/etc/bashrc
數(shù)組
定義數(shù)組
IPTS=(10.0.0.1 10.0.0.2 10.0.0.3)
顯示數(shù)組的所有元素
echo ${IPTS[@]}
顯示數(shù)組元素個數(shù)
echo ${#IPTS[@]}
顯示數(shù)組的第一個元素
echo ${IPTS[0]}
轉義和引用
特殊字符:一個字符不僅有字面意義,還有元意(meta-meaning)
# 注釋
; 分號
\ 轉義符號
" 和 ' 引號
單個字符的轉義
\n \r \t 單個字母的轉義
\$ \" \\ 單個非字母的轉義
引用
"" 雙引號,如果里面有變量,會進行解釋
'' 單引號不會進行解釋
` 反引號
運算符
賦值運算符
= 賦值運算符,用于算數(shù)賦值和字符串賦值
使用 unset 取消為變量的賦值
= 除了作為賦值運算符還可以作為測試操作符
算數(shù)運算符
基本運算符
+ - * / ** %
使用expr進行計算
expr 4 + 5 (要有空格,只能支持整數(shù))
num1=`expr 4 + 5`
數(shù)字常量的使用方法,如果不用特殊方法,a=4+5,其實把 “4+5”字符串賦值給a
let “變量名=變量值”
變量值使用0開頭為八進制,0x開頭為十六進制
雙圓括號是let命令的簡化
((a=4+5))
((a++))
echo $((10+20))
特殊符號大全
引號
' 完全引用
" 不完全引用
` 執(zhí)行命令
括號
() (()) $() 圓括號
單獨使用圓括號會產(chǎn)生一個子shell(xyz=123)
數(shù)組初始化 IPS=(ip1 ip2 ip3)
[] [[]] 方括號
單獨使用方括號是測試(test)或數(shù)組元素功能
兩個方括號表示測試表達式
<> 尖括號 重定向符號
{} 花括號
輸出范圍 echo{0..9},會輸出0-9所有數(shù)字
文件復制 cp -v /etc/passwd /etc/passwd.bak
等同于 cp -v /etc/passwd{,.bak}
運算和邏輯符號
+-*/% 算數(shù)運算符
><= 比較運算符
&& || !邏輯運算符
(( 5 > 4 && 6> 5)),然后通過 echo $? 判斷
轉義符號
\
其他符號
# 注釋符
; 命令分隔符
case 語句的分隔符要轉義 ;;
:空指令
. 和source命令相同
~ 家目錄
, 分隔目錄
* 通配符
? 條件測試或通配符
$ 取值符號
| 管道符
& 后臺運行
空格
測試和判斷
退出程序命令
exit 判斷上一條命令是否正常,0或者非0
exit 1或者0 返回10 給shell ,返回值非0位不正常退出
$? 判斷當前shell前一個進程是否正常退出
測試命令test
test命令用于檢查文件或者比較值
test可以做以下測試
文件測試
整數(shù)比較測試
字符串測試
test測試語句可以簡化為[]符號
test -f /etc/passwd2 判斷文件是否存在并且是個普通文件,-e是文件或者目錄,-d目錄
[ -d /etc/ ]
[]符號還有擴展寫法 [[]] 支持 && || < >
if
if-then 語句的基本用法
if [ 測試條件成立 ] 或 命令返回值是否為0
then 執(zhí)行相應命令
fi 結束
if-then-else 語句可以在條件不成立時也運行相應的命令
if [ 測試條件成立 ]
then 執(zhí)行相應命令
else 測試條件不成立,執(zhí)行相應命令
fi 結束
if [ 測試條件成立 ]
then 執(zhí)行相應命令
elif [ 測試條件成立 ]
then 執(zhí)行相應命令
else 測試條件不成立,執(zhí)行相應命令
fi 結束
嵌套 if 的使用
if 條件測試中可以再嵌套 if 條件測試
if [ 測試條件成立 ]
then 執(zhí)行相應命令
if [測試條件成立]
then 執(zhí)行相應命令
fi
fi
case
case 語句和 select 語句可以構成分支
case "$變量" in
"情況1" )
命令...;;;
"情況2" )
命令...;;;
* )
命令...;;;
esac
for
for 循環(huán)的語法
for 參數(shù) in 列表
do 執(zhí)行的命令
done 封閉一個循環(huán)
使用反引號或 $() 方式執(zhí)行命令,命令的結果當做列表進行處理
列表中包含多個變量,變量用空格分隔
for i in {0..9}
for filename in 'ls *.mp3'
對文本處理,要使用文本查看命令取出文本內(nèi)容
默認逐行處理,如果文本出現(xiàn)空格會當做多行處理
C 語言風格的 for 命令
for((變量的初始化;循環(huán)判斷條件;變量變化))
do
命令
done
while
while test測試是否成立
do
命令
done
until 循環(huán) 與while 循環(huán)相反,循環(huán)測試為假時,執(zhí)行循環(huán),為真實循環(huán)停止
break continue
break 退出
continue 結束本輪循環(huán)
使用循環(huán)處理位置參數(shù)
命令行參數(shù)可以使用 $1 $2 ... ${10}..$n 進行讀取
$0 代表腳本名稱
$* 和 $@ 代表所有位置參數(shù)
$# 代表位置參數(shù)的數(shù)量
有腳本test.sh如下:
#! /bin/bash
# help display help help
for pos in $*
do
if [ "$pos" = "help"]; then
echo $pos $pos
fi
done
運行語句:
bash test.sh a b c help
while 腳本如下:
#! /bin/bash
while [ $# -ge 1]
do
if [ "$1" = "help" ]; then
echo $1 $1
fi
shift
done
shift能夠參數(shù)左移
運行語句:
bash test.sh a b c help
自定義函數(shù)
函數(shù)用于“包含”重復使用的命令集合
自定義函數(shù)
function fname(){
命令
}
函數(shù)的執(zhí)行
fname
函數(shù)作用范圍的變量
local 變量名
函數(shù)的參數(shù)
$1 $2...$n
checkpid() {
local i
for i in $* ; do
[ -d "/proc/$i" ] && return 0
done
return 1
}
執(zhí)行時
checkpid 1 或者 checkpid 1 2
echo $?
系統(tǒng)腳本
系統(tǒng)自建了函數(shù)庫,可以在腳本中引用
/etc/init.d/functions
自建函數(shù)庫
使用 source 函數(shù)腳本文件“導入”函數(shù)
source /etc/init.d/functions
echo_success
腳本優(yōu)先級任務
可以使用 nice 和 renice 調整腳本優(yōu)先級
避免出現(xiàn)“不可控的”死循環(huán)
死循環(huán)導致cpu占用過高
死循環(huán)導致死機
ulimit -a 可以查看當前終端的使用限制,root用戶的話有些限制不會生效
max user processes 用戶的最大進程數(shù)
任務計劃
at 18:31
at > echo hello > /tmp/test.txt
at>
然后ctrl +d 提交
cron
配置方式
crontab -e
查看現(xiàn)有的計劃任務
crontab -l
配置格式
分鐘,小時,日期,月份,星期,執(zhí)行的命令
注意命令的路徑問題
日志(可以查看計劃任務有沒有被執(zhí)行)
/var/log/cron
每個用戶都有自己的計劃任務目錄
/var/spool/cron/用戶
任務計劃加鎖
如果計算機不能按照預期時間運行
anacontab 延時計劃任務
flock 鎖文件
正則表達式和文本搜索
元字符
. 匹配除換行符外的任意單個字符
* 匹配任意一個跟在它前面的字符
[] 匹配方括號中的字符類中的任意一個
^ 匹配開頭
$ 匹配結尾
\ 轉義后面的特殊字符
擴展元字符
+ 匹配前面的正則表達式至少出現(xiàn)一次
? 匹配前面的正則表達式出現(xiàn)零次或一次
| 匹配它前面或后面的正則表達式
grep 搜索
grep test /root/test.txt
cd /etc
find passwd
-regex 區(qū)分大小寫
-iregex 不區(qū)分大小寫
find /etc -name pass*
find /etc -regex .*wd
類型匹配
find /etc -type f -regex .*wd
時間匹配,最基礎的時間戳包括:-atime/-mtime/-ctime
find /etc/ -atime 8 -regex .*wd
刪除.txt文件
find * txt -exec rm -v {} \;
sed awk xargs
sed 的基本工作方式
-將文件以行為單位讀取到內(nèi)存(模式空間)
-使用sed的每個腳本對該行進行操作
-處理完成后輸出該行
sed 一般用于對文本內(nèi)容做替換
sed '/user1/s/user1/u1' /etc/passwd
sed 's/old/new/' filename
sed -e 's/old/new/' -e 's/old/new/' filename
sed -i 's/old/new/' -i 's/old/new/' filename
sed -r 's/(a*b)/\1 \1' filename
head -5 /etc/passwd | sed 's/...//'
head -5 /etc/passwd | sed 's/s*sbin //'
sed指令擴展
s/old/new標志位
數(shù)字.第幾次出現(xiàn)才替換
g,每次出現(xiàn)都進行替換
p,打印模式空間的內(nèi)容
sed -n 阻止默認輸出
w file 將模式空間的內(nèi)容寫入到文件
sed 's/root/!!!/2'
sed 's/root/!!!/g'
sed -n 's/root/!!!/w /tmp/a.txt'
sed '1,3s/root/!!!/2' 第一行和第三行進行替換
sed '1,$s/root/!!!/2' 第一行到最后一行進行替換
尋址可以匹配多條命令
/regular/{ 's/old/new/' ; 's/old/new/'}
可以將選項保存為文件,使用-f加載腳本文件
sed -f sedscript filename
awk 基本用法
awk 一般用于對文本內(nèi)容進行統(tǒng)計,按需要的格式進行輸出
cut 命令:cut -d:-f 1/etc/passwd
awk 命令:awk -F: '/wd$/{print$1}' /etc/passwd
awk '/^menu/{print $0}' /boot/grub2/grub.cfg
awk -F "'" '/^menu/{print $2}' /boot/grub2/grub.cfg
awk -F "'" '/^menu/{print x++, $2}' /boot/grub2/grub.cfg
awk 表達式
系統(tǒng)變量
FS和OFS字段分隔符,OFS表示輸出的字段分隔符
RS記錄分隔符
NR FNR行數(shù)
NF字段數(shù)量,最后一個字段內(nèi)容可以用$NF取出
head -5 /etc/passwd | awk 'BEGIN{FS=":"}{print $1}'
head -5 /etc/passwd | awk 'BEGIN{FS=":";OFS="---"}{print $1,$2}'
head -5 /etc/passwd | awk '{print NR,$0}'
awk '{print FNR,$0}' /etc/passwd /etc/passwd
head -5 /etc/passwd | awk 'BEGIN{FS=":"}{print $NF}'
awk '{if($2>80){print $1 ; print $2}}' kpi.txt
head -1 kpi.txt | awk '{for(c=2;c<=NF;c++) print c}'
head -1 kpi.txt | awk '{for(c=2;c<=NF;c++) print $c}'
xargs是將標準輸入轉為命令行參數(shù)
echo "a b c" | xargs mkdir
大多數(shù)情況下xargs命令都是跟著管道一起使用的
,但是,也可以單獨使用,在輸入xargs按下回車鍵,
命令行就會等待用戶輸入,作為標準輸入,你可以輸入
任意內(nèi)容然后按下ctrl + d 表示輸入結束,這時echo命令就會把前面的結果打印出來
-d指定分隔符
echo -e "a\tb\tc" | xargs -d "\t" echo -n