Shell學習筆記

SHELL的種類

  • Bourne Shell(/usr/bin/sh或/bin/sh)
  • Bourne Again Shell(/bin/bash)
  • C Shell(/usr/bin/csh)
  • K Shell(/usr/bin/ksh)
  • Shell for Root(/sbin/sh)

SHELL的程序結(jié)構(gòu)

#!/bin/bash
# 單行注釋用#號
:<<'多行注釋,<<后面也可以使用其他符號,前后要匹配一致
注釋內(nèi)容...
注釋內(nèi)容...
注釋內(nèi)容...
'
echo "Hello World !"
echo "執(zhí)行的文件名:$0";  # 執(zhí)行的文件名(包含文件路徑)
echo "第一個參數(shù)為:$1";  # 第一個參數(shù) 1
echo "第二個參數(shù)為:$2";  # 第二個參數(shù) 2
echo "第三個參數(shù)為:$3";  # 第三個參數(shù) 3
# 另外,還有幾個特殊字符用來處理參數(shù):
$# # 傳遞到腳本的參數(shù)個數(shù)
$* # 以一個單字符串顯示所有向腳本傳遞的參數(shù)。等價于 "1 2 3"
$@ # 與$*相同,但是使用時加引號,并在引號中返回每個參數(shù)。等價于 "1" "2" "3"
$$ # 腳本運行的當前進程ID號
$! # 后臺運行的最后一個進程的ID號
$- # 顯示Shell使用的當前選項,與[set命令]功能相同。
$? # 顯示最后命令的退出狀態(tài)。0表示沒有錯誤,其他任何值表明有錯誤。
$0 返回執(zhí)行shell名稱  # basename命令可以返回不包含路徑的腳本名

#! 是一個約定的標記,它告訴系統(tǒng)這個腳本需要什么解釋器來執(zhí)行,即使用哪一種 Shell。

SHELL的運行方法

  1. 作為可執(zhí)行程序
chmod +x ./test.sh  #使腳本具有執(zhí)行權(quán)限
./test.sh  1 2 3 #執(zhí)行腳本,向腳本傳遞三個參數(shù) 1 2 3

注意,一定要寫成 ./test.sh,而不是 test.sh,運行其它二進制的程序也一樣,直接寫 test.sh,linux 系統(tǒng)會去 PATH 里尋找有沒有叫 test.sh 的,而只有 /bin, /sbin, /usr/bin,/usr/sbin 等在 PATH 里,你的當前目錄通常不在 PATH 里,所以寫成 test.sh 是會找不到命令的,要用 ./test.sh 告訴系統(tǒng)說,就在當前目錄找。

  1. 作為解釋器參數(shù)
/bin/sh test.sh # 這種方式運行的腳本,不需要在第一行指定解釋器信息,寫了也沒用。
bash test.sh
sh test.sh
# 推薦下面的去執(zhí)行
source test.sh # 沒有權(quán)限的腳本不能直接被執(zhí)行,但是可以通過source或者.空格來執(zhí)行
. test.sh # .+空格+shell文件名

3.查看執(zhí)行結(jié)果碼

echo $?
    正常 : 0
    異常 : 0以外的正整數(shù),如1:無效的參數(shù),126:沒有權(quán)限執(zhí)行,127:無效的命令
exit 常量或變量  # 自定義程序返回碼,0~255

變量

定義變量時,變量名不加美元符號($,PHP語言中變量需要),如:

# 自定義變量 
say_hi=hello,world  # 不加引號時,值里有變量的會被解析后再輸出
say_hi='hello,world' # 單引號時,不轉(zhuǎn)義不解析變量
say_hi="hello,world"  # 雙引號時,值里有變量的會被解析后再輸出,有命令要反引號一下(``)
# 自定義環(huán)境變量 /etc/profile-> ~/.bash_profile->~/.bashrc->/etc/bashrc
export 變量名=value # 1.變量名=value 2. export 變量名 的合并寫法
declare -x 變量名=value
# 環(huán)境變量,一般是指用export內(nèi)置命令導出的變量
export TOMCAT=/home/tom
# 有3個命令可以顯示變量的值
:<<'
set命令輸出所有的變量,包括全局變量和局部變量;set -o命令顯示bash Shell的所有參數(shù)配置信息。
env命令只顯示全局變量;
declare命令輸出所有的變量、函數(shù)、整數(shù)和已經(jīng)導出的變量。
'

使用一個定義過的變量,只要在變量名前面加美元符號即可,如:

say_hi="hello,world"
echo $say_hi
echo ${say_hi} 
# 加花括號是為了幫助解釋器識別變量的邊界,比如下面這種情況:
for skill in Ada Coffe Action Java; do
    # 如果不給skill變量加花括號,寫成echo "I am good at $skillScript",解釋器就會把$skillScript當成一個變量(其值為空)
    echo "I am good at ${skill}Script"
done
# 只讀變量,使用 readonly 命令可以將變量定義為只讀變量,只讀變量的值不能被改變。
myUrl="https://www.google.com"
readonly myUrl
# 刪除變量,  變量被刪除后不能再次使用。
unset myUrl # unset 命令不能刪除只讀變量。
# 引號拼接字符串
greeting="hello, "$your_name" !"
greeting_1="hello, ${your_name} !"
echo $greeting  $greeting_1
# 獲取字符串長度
string="abcd"
echo ${#string}   # 輸出 4,變量為數(shù)組時,${#string} 等價于 ${#string[0]}:
# 切片,提取子字符串
string="runoob is a great site"
echo ${string:1:4} # 輸出 unoo,注意:第一個字符的索引值為 0。
# 查找子字符串
string="runoob is a great site"
echo `expr index "$string" io`  # 輸出 4,查找字符 i 或 o 的位置(哪個字母先出現(xiàn)就計算哪個):
# 定義數(shù)組
array_name=(value0 value1 value2 value3)  # 數(shù)組名=(值1 值2 ... 值n)
array_name[0]=value0
# 讀取數(shù)組
valuen=${array_name[n]} # ${數(shù)組名[下標]}
echo ${array_name[@]}  # 使用 @ 符號可以獲取數(shù)組中的所有元素
length=${#array_name[*]} # 或者*獲取數(shù)組中的所有元素(個數(shù))

運算符

原生bash不支持簡單的數(shù)學運算,但是可以通過其他命令來實現(xiàn),例如 awk 和 expr,expr 最常用。

  • 算術運算符
#!/bin/bash
a = 10
b = 20
# 通過方括號實現(xiàn)計算
$[ operation ] 
echo $[a * b]  # 結(jié)果為 200。

# 通過expr命令實現(xiàn)計算
echo `expr $a + $b` # 結(jié)果為 30。
echo `expr $a \* $b` # 結(jié)果為 200。
echo `expr $b / $a` # 結(jié)果為 2。
echo `expr $b % $a` # 結(jié)果為 0。

# 通過bash bc計算器實現(xiàn)計算
c = $(bc << EOF    # -q選項可以不顯示歡迎信息,通過print打印計算結(jié)果
scala=4    # 定義4位小數(shù)
a=10
b=20
a * b
EOF
)
echo c

echo a=$b # 賦值,把變量 b 的值賦給 a。
echo [ $a == $b ] # 比較兩個數(shù)字,返回 false。
echo [ $a != $b ] # 不相等,返回 true。
  • 關系運算符
#!/bin/bash
a = 10
b = 20
echo [ $a -eq $b ] # 檢測兩個數(shù)是否相等,返回 false。
echo [ $a -ne $b ] # 不相等,返回 true。
echo [ $a -gt $b ] # 大于,返回 false。
echo [ $a -lt $b ] # 小于,返回 true。
echo [ $a -ge $b ] # 大于等于,返回 false。
echo [ $a -le $b ] # 小于等于,返回 true。
  • 布爾運算符
#!/bin/bash
a = 10
b = 20
echo [ ! false ] # 非運算,返回 true。
echo [ $a -lt 20 -o $b -gt 100 ] # 或運算,返回 true。
echo [ $a -lt 20 -a $b -gt 100 ] # 與運算,返回 false。
echo [[ $a -lt 100 && $b -gt 100 ]] # 邏輯的 AND,返回 false
echo [[ $a -lt 100 || $b -gt 100 ]] # 邏輯的OR返回 true
  • 字符串運算符
#!/bin/bash
a = "abc"
b = "efg"
echo [ $a = $b ] # 檢測兩個字符串是否相等,返回 false。
echo [ $a != $b ] # 是否不相等,返回 true。
echo [ -z $a ] # 字符串長度是否為0,返回 false。
echo [ -n "$a" ] # 字符串長度是否不為 0,返回 true。
echo [ $a ] 返回 # 字符串是否不為空,true。
  • 文件測試運算符
#!/bin/bash
echo [ -d $file ]  # 檢測文件是否是目錄,如果是,則返回 true。
echo[ -f $file ] # 是否是普通文件,返回 true。
echo [ -r $file ] # 是否可讀,返回 true。
echo [ -w $file ] # 是否可寫,返回 true。
echo [ -x $file ] # 是否可執(zhí)行,返回 true。
echo [ -s $file ] # 檢測文件是否為空(文件大小是否大于0),不為空返回 true。
echo [ -e $file ] # 檢測文件(包括目錄)是否存在,如果是,則返回 true。

命令

  • echo
#!/bin/bash
# 顯示普通字符串:
echo "It is a test"  # 這里的雙引號完全可以省略,以下命令與上面實例效果一致:
echo It is a test
# 顯示轉(zhuǎn)義字符
echo "\"It is a test\""  # "It is a test"
# 顯示變量
read name # 從標準輸入中讀取一行
echo "$name It is a test"  # 把輸入行的每個字段的值指定給 shell 變量 + It is a test
# 顯示換行
echo -e "OK! \n" # -e 開啟轉(zhuǎn)義
# 顯示不換行
echo -e "OK! \c" # -e 開啟轉(zhuǎn)義 \c 不換行
# 顯示結(jié)果定向至文件
echo "It is a test" > myfile
# 原樣輸出字符串,不進行轉(zhuǎn)義或取變量(用單引號)
echo '$name\"'   # $name\"
# 顯示命令執(zhí)行結(jié)果
echo `date`  # Thu Jul 24 10:08:46 CST 2022
  • printf
#!/bin/bash
echo "Hello, Shell"  # Hello, Shell
printf "Hello, Shell\n" # echo同樣的結(jié)果,手動添加 \n
# 格式替代符 %s %c %d %f類型,%-10s指一個寬度為 10 個字符(- 表示左對齊,沒有則表示右對齊)
printf "%-10s %-8s %-4s\n" 姓名 性別 體重kg   
printf "%-10s %-8s %-4.2f\n" 郭靖 男 66.1234
  • test
#!/bin/bash
# 用于檢查某個條件是否成立,它可以進行數(shù)值、字符和文件三個方面的測試。
num1=100
num2=100
if test $[num1] -eq $[num2]  # 兩個數(shù)相等!
then
    echo '兩個數(shù)相等!'
else
    echo '兩個數(shù)不相等!'
fi
cd /bin
if test -e ./notFile -o -e ./bash  # 如果文件存在則為真 ,與( -a )、或( -o )、非( ! )
then
    echo '至少有一個文件存在!'
else
    echo '兩個文件都不存在'
fi

流程控制

  • 分支
#!/bin/bash
# if后面接命令,返回碼為0則執(zhí)行then語句,否則else語句。通過test命令才可實現(xiàn)表達式的判定
# 單括號允許在if語句中使用子shell
# 雙括號命令允許在test比較過程中使用高級數(shù)學表達式
# 雙方括號命令提供了針對字符串比較的高級特性
# 單分支
if [ $(ps -ef | grep -c "ssh") -gt 1 ]; then echo "true"; fi
# 多分支
a=10
b=20
if [ $a == $b ]
then
   echo "a 等于 b"
elif [ $a -gt $b ]
then
   echo "a 大于 b"
elif [ $a -lt $b ]
then
   echo "a 小于 b"
else
   echo "沒有符合的條件"
fi
# case ... esac
echo '輸入 1 到 4 之間的數(shù)字:'
echo '你輸入的數(shù)字為:'
read aNum
case $aNum in
    1)  echo '你選擇了 1'
    ;;
    2)  echo '你選擇了 2'
    ;;
    3)  echo '你選擇了 3'
    ;;
    4)  echo '你選擇了 4'
    ;;
    *)  echo '你沒有輸入 1 到 4 之間的數(shù)字'
    ;;
esac
  • 循環(huán)
#!/bin/bash
# for 循環(huán)  for var in list
# 環(huán)境變量IFS=$'\n'  or \t  ,internal field separator,內(nèi)部字段分隔符
for var in item1 item2 ... itemN; do command1; command2… done;
for loop in 1 2 3 4 5
do
    echo "The value is: $loop"
done > output.txt # 結(jié)果輸出到output.txt而非屏幕上
# while 循環(huán)
int=1
while(( $int<=5 ))
do
    echo $int
    let "int++"
done
# until 循環(huán)
a=0

until [ ! $a -lt 10 ]
do
   echo $a
   a=`expr $a + 1`
done
# break 跳出所有循環(huán)(終止執(zhí)行后面的所有循環(huán)), break n 跳出n層循環(huán)
# continue 不會跳出所有循環(huán),僅僅跳出當前循環(huán)。continue n 繼續(xù)執(zhí)行n級循環(huán)

函數(shù)

#!/bin/bash
funWithReturn(){
    echo "這個函數(shù)會對輸入的兩個數(shù)字進行相加運算..."
    echo "輸入第一個數(shù)字: "
    read aNum
    echo "輸入第二個數(shù)字: "
    read anotherNum
    echo "兩個數(shù)字分別為 $aNum 和 $anotherNum !"
    return $(($aNum+$anotherNum)) # 如果不加,將以最后一條命令運行結(jié)果,作為返回值。 return后跟數(shù)值n(0-255)
}
funWithReturn  # 調(diào)用函數(shù)時可以向其傳遞參數(shù)。在函數(shù)體內(nèi)部,通過 $n 的形式來獲取參數(shù)的值,無須括號
echo "輸入的兩個數(shù)字之和為 $? !"  # 函數(shù)返回值在調(diào)用該函數(shù)后通過 $? 來獲得。

SHELL的IO交互

  • /dev/null 文件
    /dev/null 是一個特殊的文件,寫入到它的內(nèi)容都會被丟棄;如果嘗試從該文件讀取內(nèi)容,那么什么也讀不到。但是 /dev/null 文件非常有用,將命令的輸出重定向到它,會起到"禁止輸出"的效果。如果希望執(zhí)行某個命令,但又不希望在屏幕上顯示輸出結(jié)果,那么可以將輸出重定向到 /dev/null
# 如果希望屏蔽 stdout 和 stderr,可以這樣寫:
command > /dev/null 2>&1
  • 輸出重定向
# 文件描述符 0 通常是標準輸入(STDIN),1 是標準輸出(STDOUT),2 是標準錯誤輸出(STDERR)
command > file1  # 輸出重定向會覆蓋文件內(nèi)容
command >> file1  # 如果不希望文件內(nèi)容被覆蓋,可以使用 >> 追加到文件末尾
  • 輸入重定向
# 需要從鍵盤獲取輸入的命令會轉(zhuǎn)移到文件讀取內(nèi)容
command < file1
command << EOF  # 直到輸入EOF才會停止接收

SUB調(diào)用

#!/bin/bash
# 封裝一些公用的代碼作為一個獨立的文件,然后【. 文件名】來調(diào)用,F(xiàn)ULLPATH
. filename   # 注意點號(.)和文件名中間有一空格
source filename # 或者這樣調(diào)用其他文件
# 被調(diào)用的文件 filename 不需要可執(zhí)行權(quán)限。

Linux三劍客

  • grep
    在文件或標準輸入中搜索指定的字符串或正則表達式,并輸出包含該字符串或匹配該正則表達式的所有行
grep "error" logfile.txt
  • sed
    用于編輯文本流的流編輯器,可以對輸入的文本進行替換、刪除、插入和打印等操作(不會修改源文件)。
sed 's/old/new/g' file.txt  # 將file.txt文件中所有 "old" 替換為 "new" g替換全部,w可寫入文件
    -e 執(zhí)行多個命令# sed -e 's /old/new;s/my/you/ test.txt'  命令之間必須以分號(;)分隔
    -f 指定從文件讀取sed命令  # sed -f command.sed  file.txt
    -n 命令執(zhí)行后不顯示屏幕信息,sed -n ’s/old/new/p’ ,加了p則表示屏幕顯示替換后文本信息

替代字符/
    sed編輯器允許選擇其他字符作為替換命令的替代分隔符
    sed 's!/bin/bash!/bin/csh' /etc/passwd  # 感嘆號(!)被用作替換命令的分隔符

使用地址
    sed '2s/dog/cat/' data.txt  # 第二行的dog變cat
    sed '2,3s/dog/cat/' data.txt  # 2-3行區(qū)間的被替換
    sed '^&s/dog/cat/' data.txt  # 開頭到結(jié)尾的被替換
使用文本模式過濾
    sed '/rich/s/bash/csh/' etc/passwd  # 替換只應用于包含匹配模式的行,只修改用戶rich的默認shell
使用命令組
    sed '2,{    # 可以用花括號將其組合在一起執(zhí)行
    >s/old/new/
    >s/cat/dog/
    }' data.txt
單行next命令
sed '/Header/{n;d}' data.txt  # 先查找Header的那一行,找到之后next命令會移動到文本的下一行
多行next命令,合并文本行
sed '/Frist/{N;s/\n/ /}' data.txt  # 先查找First那行,使用N命令將下一行與該行合并,然后將換行符(\n)替換成空格
多行刪除
sed 'N;/System\nAdmin/D'data.txt
多行打印
sed 'N;/System\nAdmin/P'data.txt

刪除

sed 'd' data.txt  # 刪除全部文本
sed '3d' data.txt  # 刪除指定文本
sed '/number 1/d'data.txt  # 匹配到number 1的行被刪除

插入

當使用插入命令時,文本會出現(xiàn)在數(shù)據(jù)流文本之前
  插入(insert)(i)命令會在指定行前增加一行
    echo "line 2" | sed 'i \line 1'  # 結(jié)果是line 1 換行l(wèi)ine2
  附加(append)(a)命令會在指定行后增加一行
    echo "line 1" | sed 'a \line 2'  # 結(jié)果是line 2 換行l(wèi)ine1
    sed '$a \   # 末尾追加多行,末尾必須追加反斜線
    > text1
    > text2
    ' data.txt

修改

修改(change)(c)命令允許修改數(shù)據(jù)流中整行文本的內(nèi)容
  sed '2c\  # 修改第二行
  > line2
  'data.txt

sed '/test 1/c\  # 把匹配到的test 1 替換成text 2
>text 2
>'data.txt

轉(zhuǎn)換

轉(zhuǎn)換(y)命令是唯一可以處理單個字符的sed編輯器命令
  sed 'y/123/789/'data.txt  # 把inchar的第一個字符替換成outchar的第一個字符
  • awk
    一種文本處理工具,可用于對文本進行格式化和轉(zhuǎn)換。它可以讀取文本文件、執(zhí)行數(shù)學運算、進行邏輯操作、創(chuàng)建變量和數(shù)組等,gawk:GNU版本,屬于編程語言級別
awk '{ sum += $1 } END { print sum }' numbers.txt  # 計算文件中所有數(shù)字的總和,Ctrl+D等于EOF
awk '{print $1}' file.txt 從 file.txt 文件中提取第一列,即每行第一個字段,默認分隔符時空白
    -F 指定分隔符,awk -F:  '{print $1}' /etc/passwd  ,F后面指定冒號分隔符
                  awk -F: -f command.awk /etc/passwd ,f跟sed一樣從文件讀取命令
    ;分號  使用多條命令時用分號拼接
    $0 表示整個文本行
    $1...n  表示第幾個字段,即第幾列
    BEGIN  讀取數(shù)據(jù)前執(zhí)行BEGIN關鍵字之后指定的腳本
    END  指定一段腳本,gawk會在處理完數(shù)據(jù)后執(zhí)行這段腳本
    gawk 'BEGIN {print "The data3 FILE Contens:"}
    >{print $}
    >END {print "End of File}' data3.txt
gawk 'BEGIN {FS=","} {print $1,$2,$3}'  data  # 逗號,分割字段,并打印第1,2,3列
gawk 'BEGIN {FS=",";OFS="-"} {print $1,$2,$3}'  data # 逗號分隔后用-連接第1,2,3列

正則表達式

在 Linux 系統(tǒng)中,正則表達式經(jīng)常被用來進行文件搜索、文本處理、日志分析等操作。例如,可以使用 grep 命令來搜索包含某個正則表達式的文件,使用 sed 命令來對文本進行替換或刪除等操作。

字符類 []:
  匹配一組字符中的任意一個字符。例如,[abc] 匹配字符 a、b 或 c。

元字符 .:
  匹配除了換行符之外的任意單個字符。例如,a.b 匹配 "aab"、"abb"、"acb" 等。

量詞 {}:
  用來指定某個模式的匹配次數(shù)。例如,a{3} 匹配 "aaa",a{1,3} 匹配 "a"、"aa" 或 "aaa"。

字符轉(zhuǎn)義 \:
  用于將具有特殊含義的字符轉(zhuǎn)義為字面值。例如,\. 匹配 "."。

分組 ():
  用于將多個模式組合成一個整體,以便對整個組合進行量詞或轉(zhuǎn)義。例如,(abc)+ 匹配 "abc"、"abcabc" 等。

錨點 ^和$:
  用于匹配文本的開頭和結(jié)尾。例如,^abc 匹配以 "abc" 開頭的字符串,xyz$ 匹配以 "xyz" 結(jié)尾的字符串。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

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

  • 走進 Shell 編程的大門 什么是 Shell? 簡單來說,Shell編程就是對一堆Linux命令的邏輯化處理。...
    趙客縵胡纓v吳鉤霜雪明閱讀 1,271評論 0 32
  • 1.Shell腳本 1.1 格式 首行 #!/bin/bash 指定解釋器 1.2 注釋 '#'開頭的行,'...
    keep_moving閱讀 1,299評論 4 45
  • 最近在做一個作業(yè),需要篩選文檔里面的內(nèi)容。在網(wǎng)上谷歌到這個函數(shù)之后發(fā)現(xiàn)簡直不要太好用!介紹一下 首先,awk好像不...
    王宇涵_e5f1閱讀 275評論 0 0
  • 一、調(diào)試腳本 調(diào)試功能是每一種編程語言都應該實現(xiàn)的重要特性之一,當出現(xiàn)一些始料未及的情況時,用它來生成腳本運行信息...
    小喜_ww閱讀 698評論 1 4
  • 嘛,作為習慣使用Mac作為開發(fā)系統(tǒng)的開發(fā)者,Shell算是必須學習的內(nèi)容之一。CI的腳本之類的也需要用Shell來...
    優(yōu)雨閱讀 296評論 0 0

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