Shell(二)

什么是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 {} \;

Linux find命令常用用法示例

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
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容