【網路安全】Shell 指令碼學習

D1TAsec發表於2024-11-27

宣告:學習影片來自 b 站 up 主 瀧羽 sec,如涉及侵權馬上刪除文章

宣告:本文主要用作技術分享,所有內容僅供參考。任何使用或依賴於本文資訊所造成的法律後果均與本人無關。請讀者自行判斷風險,並遵循相關法律法規。

指令碼建立執行與變數使用

首先進入Linux終端【Windows系統可以使用MobaXterm中的zsh/bash終端】,可以使用 vim 建立一個 .sh 結尾的檔案。
在檔案的第一行寫入下列三種中的其中一種,這些是指令碼直譯器

  • #!/bin/bash 等是一個特殊的行,稱為 shebang(也稱為 hashbang)。它出現在指令碼檔案的第一行。這一行的作用是告訴作業系統應該使用哪個直譯器來執行這個指令碼。
#!/bin/bash
#!/bin/dash
#!/bin/sh
  • 在許多 Linux 系統中,/bin/sh(傳統的 Bourne shell)實際上是指向 /bin/dash 的符號連結。dash(Debian Almquist Shell)是一個輕量級的 shell,它被設計用來提供基本的指令碼執行功能,並且在啟動速度和資源佔用方面有一定的優勢。
  • 當一個指令碼沒有指定直譯器(即沒有#!/bin/bash 或其他明確的直譯器路徑的 shebang 行),系統會預設使用 /bin/sh 來解釋執行這個指令碼。由於 /bin/sh 常常是 /bin/dash 的連結,所以在這種情況下,指令碼實際上是由 dash 來執行的。

如果終端安裝了 zsh 等其他指令碼直譯器,可以使用 #!/bin/zsh 來進行解釋,或者 依然也可以使用 #!/bin/bash 等,此時執行時,依然會使用 bash 進行指令碼解釋,zsh 只會充當一個呼叫的角色。

在執行 .sh 結尾的shell 指令碼時,有兩種方式:

  1. chmod +x xxx.sh 新增執行許可權後,使用 ./xxx.sh 執行
  2. 使用指令碼直譯器直接執行 sh xxx.sh / bash xxx.sh / zsh xxx.sh
  3. source xxx.sh ,該命令與使用 指令碼直譯器直接執行效果一致,唯一不同的地方在於該命令會將輸出內容進行不同顏色標註。

變數

宣告變數 name="d1"
使用變數 echo $name / echo "my name is $name"
如果使用雙引號和不使用雙引號的效果是一樣的,都會將變數進行替換為變數值;
但如果是單引號,就不會對變數進行解析。

變數拼接

echo "my name is $name,and my age is $ageyears old"
上述例子中,變數age和字串years之間沒有空格,因為會導致解析為空,因為沒有定義變數,解決辦法是 使用 雙引號 或 大括號 將變數引起來
echo "my name is $name,and my age is "$age"years old"
echo "my name is $name,and my age is {$age}years old"
但是使用花括號引起來的方式,在輸出時,變數內容會被顯示在花括號中
以上所述變數均為臨時變數,變數由數字、字母和下劃線組成,但不能以數字開頭,也不能中間存在空格,可以使用下劃線代替。

檢視定義的變數

如果在終端直接定義變數,那麼需要檢視定義的變數時,可以使用
set | grep name
刪除變數
unset name

永久環境變數和字串顯位

Windows中的環境變數在 path 下新增
which ls 在Linux下檢視ls命令所在位置
echo $PATH Linux輸出環境變數
檢視輸出結果存在/usr/bin目錄什麼意思呢就是當我們執行ls它會幫我們找到對應得目錄做一個執行,也就是ls的完整路徑應該是/usr/bin/ls指令碼

根據上述描述,我們可以直接將我們的指令碼新增至環境變數使其可以直接執行:

  1. 將寫好的指令碼 1.sh 移動到環境變數 /usr/bin 等任意一個目錄下,就可以在終端直接執行 1.sh
  2. 將整個目錄都新增到環境變數中,這樣整個目錄下的檔案都可以直接執行。例如:將 /root/ 目錄新增到環境變數中, /usr/bin:/bin:/usr/bin:/drives/c/windows:/root/
    1. 使用命令 export PATH=/root:$PATH
    2. export 命令是一個用於設定環境變數的關鍵字,使得設定的變數可以在當前shell以及由該shell啟動的子程序中生效。
    3. PATH:這是一個非常重要的環境變數,它定義了系統在哪些目錄下去尋找可執行程式。當你在命令列輸入一個命令(如Is、cat等)時,系統會根據PATH環境變數所指定的目錄順序去查詢對應的可執行檔案,找到後就執行它。
    4. /root:$PATH:這裡是在重新定義PATH的值。它將/root目錄新增到了原有的PATH變數值的最前面(假設原有的PATH值儲存在變數PATH中,這裡透過:PATH的形式保留了原來的值並新增了新的部分)。這樣做的結果是,當系統去查詢可執行程式時,會先在/root目錄下查詢,然後再按照原來PATH所指定的其他目錄順序查詢。

永久變數

修改使用者配置檔案(~/.bashrc~/.bash_profile
- 對於 bash 使用者,通常可以在使用者主目錄下的 ~/.bashrc~/.bash_profile 檔案中新增目錄到環境變數。如果使用的是 zsh,則是 ~/.zshrc。以 bash 為例,使用文字編輯器(如 vinano)開啟 ~/.bashrc 檔案。

vi ~/.bashrc
  • 在檔案末尾新增以下行(假設要新增 /home/user/permanent_bin 目錄):
export PATH=$PATH:/home/user/permanent_bin
  • 儲存並退出檔案後,要使修改生效,可以在終端中執行 source ~/.bashrc。這樣,以後每次開啟新的終端會話,/home/user/permanent_bin 目錄都會自動新增到 PATH 中。
    修改系統配置檔案(全域性設定,謹慎操作)
    • 在某些情況下,可能需要為系統的所有使用者新增目錄到環境變數。這可以透過修改系統級別的配置檔案來實現,如 /etc/profile/etc/environment
    • 例如,在 /etc/profile 檔案中新增目錄路徑。使用文字編輯器開啟 /etc/profile
vi /etc/profile
  • 找到合適的位置,新增類似以下的內容(假設要新增 /systemwide/bin 目錄):
export PATH=$PATH:/systemwide/bin
  • 儲存並退出後,這個目錄就會被新增到所有使用者的環境變數 PATH 中。不過,修改系統配置檔案可能會影響整個系統的執行,需要謹慎操作。

字串相關操作

假設我們想知道一個字串的長度,比如我們想解析一個字串的長度我們如何進行實現?
比如 name="D1" age=27 然後我們透過 echo "my name is $name,and i am $age years old" 列印完整字串

str="hello world"
echo ${#str}
輸出字串 str 的長度

echo ${str:0:3}
輸出前三個字元

指令碼引數傳遞與數學運算

向指令碼程式傳遞引數如何實現?

echo 執行的檔名是:$0
echo 第一個引數是:$1
echo 傳遞的引數作為一個字串顯示:$*
echo 傳遞的引數獨立作為每個字串顯示:$@
echo 傳遞到指令碼的引數個數是:$#
echo 最後命令的退出狀態:$?
echo 指令碼執行的當前程序ID是:$$

將上述內容新增到 2.sh 指令碼中
執行指令碼時, ./2.sh 1 2 這樣,2.sh是第一個引數,但不是傳入的第一個引數,因此 $0 就是 2.sh ,1 是傳入的第一個引數,因此 $1 就是 1。

由此得出 引數傳遞一般為 $n(n表示數字 可遞增)$* 就是將引數當作統一的字串顯示出來,而 $@ 是將每個字串當作獨立的字串顯示這也是 $*$@ 的區別,$# 代表引數的個數,$? 是檢視命令執行狀態的,如果顯示為0那麼命令就是正常執行的,其他數字就是出錯了,$$ 就是檢視指令碼當前程序id的。

在shell中進行數學運算

在shell程式設計中,利用expr進行運算
expr 5+10 回顯 5+10
expr 5 + 10 這樣寫就行了5(空格)+(空格)10
以上方法適用於加法減法,如果用乘法就會報錯。

expr 6\*6 (乘法是用\* python直接使用 * 就行了,而shell要用\進行轉義)

除法:
expr 6 / 3 / 是取整數
expr 6 % 3 % 是取餘

混合運算
expr ( 5 + 7 ) \* 2 這樣會報錯,括號依然需要轉義 expr \( 5 + 7 \) \* 2

透過變數進行運算

需要將變數內容賦值為運算表示式,使用反引號,這樣在呼叫時,就可以直接得到運算結果。

指令碼與使用者互動以及 if 條件判斷

使用shell指令碼進行互動

利用read name age指定變數資訊xiaoyu 26 ,然後利用echo $nameecho $age 來接收使用者輸入。
利用read -p "請輸入您的姓名" name age
輸入:xiaoyu 80 【這種方式輸入時,需要用空格將兩個變數分開,且一次性輸入】
echo $name(接收使用者的輸入)
-p 用於輸出後面的內容
-t 用於指定使用者輸入的事件,超時自動退出
-n 用於限制使用者輸入內容的長度

關係運算子

首先定義兩個變數,然後透過if條件判斷來進行兩個變數直接的判斷,只能對數值進行判斷,無法對字元進行判斷。

-eq 相等
-lt 小於
-gt 大於
-ne 不等於
else 反轉
num1 = 28
num2 = 36
if [ "$num1" -eq "$num2" ] ;then
	echo 相等
else 
	echo 不相等
fi

字串運算和邏輯運算子

字串運算

注意方括號後的空格,以及分號後面的空格,還有變數的引號

str1="hello"
str2="hello"
if [ "$str1" = "$str2" ]; then
	echo True
else 
	echo False
fi

注意:Linux大小寫敏感

str1="hello"
str2="hello"
if [ -z "$str1" ]; then
	echo True
else 
	echo False
fi

-z 引數,用於檢查變數長度是否為零
-n 引數,檢查變數長度是否不為零,與-t相反

str1="hello"
str2="hello"
if [ "$str1" ]; then
	echo True
else 
	echo False
fi

不設定任何引數,如果 str1為空,則返回 False,不為空,返回True。

邏輯運算

布林運算

num1=9

if [ "$str1" != "9" ]; then
	echo num1不等於9
else 
	echo num1等於9
fi

餘運算

num1=9
num2=19
if [ "$str1" != "9" -a $num2 -lt "20" ]; then
	echo True
else 
	echo False	
fi

同時滿足 $num1 != 9 -a $num2 -it 20 輸出true,不滿足返回false
與之相反的引數是-o引數,只需要滿足其中一個就可以返回true兩個都不滿足就返回flase

if 條件判斷與 for 迴圈結構

if 條件判斷

#!/bin/bash
# 定義變數
a=10
b=20

# 進行條件判斷
if [ "$a" -eq "$b" ]; then
	echo "a=b"
elif [ "$a" -gt "$b" ]; then
	echo "a>b"
else 
	echo "沒有符合上述條件"
fi

bash 指令碼中,透過 “變數名=值” 的方式就可以完成變數的定義和賦值。

for 迴圈

for num in 1 2 3 4 5
do
	echo "The number is $num"
done

這是一段使用for迴圈的程式碼片段,常見於Shell指令碼(如bash指令碼)中,用於對一系列的值進行迭代操作。

迴圈語句 for num in 1 2 3 4 5 :
for:是迴圈的關鍵字,用於開啟一個for迴圈結構。
num:定義了一個迴圈變數,在每次迴圈迭代過程中,這個變數會被賦予不同的值。
in 1 2 3 4 5 :指定了個值的列表,迴圈變數。num將會依次取這個列表中的每一個值,num會先被賦值為1,然後進行第一次迴圈;接著num會被賦值為2,進行第二次迴圈,以此類推,
直到num取完列表中的最後一個值5。

迴圈體
do:是與for迴圈起始語句配合使用的關鍵字,它標誌著迴圈體的開始。在do和後面的done之間的語句就是每次迴圈時需要執行的操作。

輸出語句 echo "The number is Snum":
echo:是一個用於在終端輸出資訊的命令。

迴圈結束
done:是for迴圈的結束關鍵字,它標誌著整個for迴圈過程結束。

for str in "hello world"
do
	echo $str
done

上述迴圈中,str 只會被賦值一次,其賦值為字串,因為值列表中只有一個字串。

for迴圈與while迴圈

for i in `seq 1 100`
do 
	echo $i
done
for i in $(seq 1 100)
do
	echo $i
done

上述兩種寫法的作用都是一樣的,使 i 從1取值到100,並輸出。

for ((i=1; i<100; i++))
do
	echo $i
done

在for迴圈的雙括號語法(())中:
初始化部分i=1是給迴圈變數i賦初值為1。
條件判斷部分i<100表示只要i的值小於100,迴圈就會繼續執行。
選代部分i++是每次迴圈結束後讓i的值自增1,這樣就能實現從1開始,每次增加1,直到1達到99(因為當1等於100時就不滿足<100這個條件了),並在每次迴圈中透過echo輸出i的當前值。

while 迴圈

i=1
while (( $i<=10 ))
do
	echo $i
	((i++))
done
i=1
while (( $i<=10 ))
do
	echo $i
	let "i++"
done

程式碼(1)
變數初始化:
首先透過i=1這一行,將變數i初始化為1,為後續的迴圈操作確定起始值。

迴圈條件判斷:
while(( $i<=10 ))是迴圈的條件判斷部分。這裡使用了雙括號(())語法,它用於進行算術表示式的計算和判斷。在每次迴圈開始前,都會檢查的值是否小於等於10。只要這個條件滿足,迴圈體內部的程式碼就會被執行。

迴圈體執行內容:
在迴圈體內部,首先透過 echo $i 這一行,將當前i的值輸出到控制檯,這樣就可以看到迴圈過程中 i 的變化情況。
接著,透過((i++))這一語句對變數i進行自增操作。這裡的(())語法同樣用於算術運算,i++表示將i的值增加1。每次迴圈結束後,i的值就會比上一次迴圈時增加1,以便在下次循
環開始時進行新的條件判斷。
let 命令用於 執行算術運算子,可以接收一個或多個算術表示式作為引數,並對相關變數執行算術操作。

until 迴圈以及函式基本建立呼叫

until 迴圈

until 直到xxx為止

i=0 # 初始化變數
until [ ! $i -lt 10 ]
do
	echo $i
	((i++))
done

這段程式碼使用 until 迴圈結構,用於在滿足特定條件之前重複執行迴圈體中的操作。
上述程式碼中,會不斷輸出 i 的值,並對 i 的值進行自增,直到 i 的條件不滿足迴圈條件。
上述迴圈條件為 i 不小於 10 時,進行不斷迴圈。
[] 的作用與 test 語句一致

[ ! $i -lt 10 ]
與
test! $i -lt 10

Case 語句

read -p "請您輸入一個數值:" num
case $num in 
	1)echo 您輸入的數字是1
	;;
	2)echo 您輸入的數字是2
	;;
	*)echo 您輸入的是其他數字
	;;
esac

上述這段程式碼的功能是,從使用者那裡獲取一個數值,根據輸入的數值進行不同的處理。
如果輸入是1,就輸出第一個字串。

獲取使用者輸入:
read -p "請您輸入一個數值:" num:這裡使用read命令來讀取使用者從鍵盤輸入的內容。p選項用於在等待輸入之前向使用者顯示提示資訊,在這個例子中,提示資訊是“請您輸入一個數值:,使用者輸入的內容會被儲存到變數num中。

case $num in:這是bash,中的case語句的起始標識,用於根據變數num的不同取值來執行不同的程式碼塊。
1)、2)和*)部分:
1):當變數num的值等於1時,會執行這部分程式碼。即echo您輸入的數字是1,然後透過;;結束這個分支的執行。
2):同理,當num的值等於2時,執行echo您輸入的數字是2,並以;;結束。
*) :這是一個萬用字元分支,當num的值既不等於1也不等於2時,就會執行這部分程式碼,即echo您輸入的是其他數字,最後也以;;結束整個case語句。

基本函式學習

DemoFunc(){
	echo "hello world"
}
DemoFunc // 單獨一行

上述程式碼是一個基本函式的建立和引用

DemoFunc(){
	echo "Hello world"
	echo "my name is $1"
}

DemoFunc xiaoyu

程式碼功能
這段程式碼定義了一個函式DemoFunc,然後呼叫了該函式並傳遞了引數xiaoyu。函式DemoFunc的功能是在被呼叫時,先輸出固定的字串“hello world”,接著輸出一個包含引數值的字串“My name is $1:”,這裡的$1表示函式接收到的第一個引數。

程式碼執行過程
函式定義:
DemoFunc():這部分宣告瞭函式名為DemoFunc(),大括號內是函式體內容。
echo “hello world":當函式被呼叫時,這是函式體中首先執行的語句,會將字串“helloworld”輸出到控制檯。
echo “My name is $1:”:在輸出“hello world”之後,會執行這條語句。由於在呼叫函式DemoFunc()時傳遞了引數xiaoyu,此時S1的值就被設定為xiaoyu,所以這條語句會輸出“My
name is xiaoyu:"。

函式呼叫:
DemoFunc xiaoyu:這行呼叫了已經定義好的DemoFunc函式,並將引數xiaoyu傳遞給它。

多函式呼叫

DemoFunc(){
	echo "hello world"
	echo "My name is $1 , and my age is $2 years old"
}
DemoFunc xiaoyu 27

不同指令碼的互相呼叫

2.sh

#!/bin/bash
echo "hello 2.sh"

3.sh

#!/bin/bash
. 2.sh
或
source 2.sh

注意:是 .空格2.sh
此時執行3.sh就會執行 2.sh的內容

變數的呼叫

1.sh

name="d1"
age=22

2.sh

source 1.sh
echo "my name is $1 , and my age is $2 years old"

重定向

重定向分為 輸入重定向和輸出重定向

ls > 1.txt
cat 1.txt

who > 1.txt
cat 1.txt

追加內容
ls >> 1.txt
cat 1.txt

如果將 ls 重定向到垃圾回收站
ls > /dev/null
不會有任何回顯

輸入重定向
dist.txt

/home/user/Document
/home/user/Pictures
/home/user/Music

使用 ls 命令加輸入重定向,檢視目錄下的檔案

ls -al < dist.txt

檔案描述符

0:標準輸入
1:標準輸出
2:錯誤輸出

例子:

ls > 3.txt 2>5.txt

如果輸出正確,就會將結果輸出到3.txt,如果錯誤,就將結果輸出到5.txt

相關文章