ShellScript腳本編程

語法基礎

腳本結構

我們先從這個小demo程序來窺探一下我們shell腳本的程序結構

#!/bin/bash# 注釋信息echo_str="hello world"test(){echo $echo_str
}test echo_str

首先我們可以通過文本編輯器(在這里我們使用linux自帶文本編輯神器vim),新建一個文件demo.sh,文件擴展名sh代表shell,表明該文件是一個shell腳本文件,并不影響腳本的執行,然后將上述代碼片段寫入文件中,保存退出

然后使用bash?-n?demo.sh命令可以檢測剛才腳本文件的語法是否錯誤,如果沒有回顯結果就代表腳本文件沒有語法錯誤

  • 腳本都以#!/bin/bash開頭,#稱為sharp!在unix行話里稱為bang,合起來簡稱就是常見的shabang#!/bin/bash?指定了shell腳本解釋器bash的路徑,即使用bash程序作為該腳本文件的解釋器,當然也可以使用其它的解釋器/bin/sh等,根據具體環境進行相應選擇
  • echo_str是字符串變量,通過$進行引用變量的值,
  • test是自定義函數名,通過函數名?傳入參數格式進行函數的調用
  • echo是shell命令,相對于python中的print
  • #字符用來注釋shell腳本的

最后可以使用下列兩種方式執行上述腳本

  • 將腳本作為bash解釋器的參數執行:此時首行的#!/bin/bash可以不用寫

    • bash?demo.sh:直接將腳本文件作為bash命令的參數
    • bash?-x?demo.sh:使用-x參數可以查看腳本的詳細執行過程
  • 將腳本作為獨立的可執行文件執行:此時首行的#!/bin/bash必須寫,用來指定shell解釋器路徑;同時腳本必須可執行權限

    • chmod?+x?demo.sh:給腳本添加執行權限
    • ./demo.sh:執行腳本文件,在這里需要使用./demo.sh表明當前目錄下腳本,因為PATH環境變量中沒有當前目錄,寫成demo.sh系統會去/sbin、/sbin等目錄下查找該腳本,無法找到該腳本文件執行,造成報錯

數據結構

數據類型的本質:固定內存大小的別名

據類型的作用:

  • 確定對應變量分配的內存大小
  • 確定對應變量所能支持的運算或操作

shell腳本是弱類型解釋型的語言,在腳本運行時由解釋器進行解釋變量在什么時候是什么數據類型

在bash中,變量默認都是字符串類型,都是以字符串方式存儲,所以在本章主要是介紹各數據類型變量所支持的運算或操作

雖說變量默認都是字符串類型,但是按照其使用場景可將數據類型分為以下幾種類型:

  • 數值型
  • 字符串型
  • 數組型
  • 列表型

數值型

首先我們來聲明定義一個數值型變量:declare?-i?Var_Name

  • 雖說聲明是一個數值型變量,但是存儲依然是按照字符串的形式進行存儲
  • 該種方式聲明,變量默認是本地全局變量,可以通過local?Var_Name關鍵字將變量修改為局部變量,可以通過export?Var_Name關鍵字將變量導出為環境變量
  • 除了使用declare?-i顯式聲明變量數據類型為數值型,還可以像Var_Name=1由解釋器動態執行隱式聲明該變量數據類型為數值型

數值型變量一般支持以下運算操作

  • 算術運算
  • 比較運算
  • 數組索引

算術運算

算數運算代碼示例如下

#!/bin/bashdeclare -i val=5   # 顯式聲明數值變量
num=2              # 隱式聲明數值變量# 使用[]運算符執行算術表達式$val+$num
# 使用$引用表達式執行結果
echo "val+num=$[$val+$num]"
echo "val++: $[val++]"  # 這里不需要加$,不是引用變量的值,而是修改變量的值
echo "val--: $[val--]"  # 這里不需要加$,不是引用變量的值,而是修改變量的值
echo "++val: $[++val]"  # 這里不需要加$,不是引用變量的值,而是修改變量的值
echo "--val: $[--val]"  # 這里不需要加$,不是引用變量的值,而是修改變量的值# 使用(())運算符執行算術表達式
# 使用$引用表達式執行結果
echo "val-num=$(($val-$num))"
echo "val%num=$(($val%$num))"# 使用let關鍵字執行算術表達式$val*$num
# 使用=運算符將執行結果賦值給變量
let ret=$val*$num
echo "var*num=$ret"# 使用expr命令執行算術表達式$val/$num但是$val / $num之間需要用空格隔開
# 此時該表達式中的各個部分將作為參數傳遞給expr命令,最后使用``運算符引用命令的執行結果
# 使用=運算符將命令引用結果賦值給變量
ret=`expr $val / $num`
echo "val/num=$ret"# 使用let關鍵字執行算術表達式+=、-=、*=、/=、%=
let val+=$num
echo "var+=num:$val"
let val-=$num
echo "var-=num:$val"
let val*=$num
echo "val*=num:$val"
let val/=$sum         # 貌似let不支持/=運算符
echo "val/=num:$val"
let val%=$num
echo "val%=num:$val"

運行結果為:

val+num=7
val++: 5
val--: 6
++val: 6
--val: 5
val-num=3
val%num=1
var*num=10
val/num=2
var+=num:7
var-=num:5
val*=num:10
test.sh: line 37: let: val/=: syntax error: operand expected (error token is "/=")
val/=num:10
val%=num:0

let 關鍵字用于執行算術運算。它主要用于對變量進行數學計算,并且可以在表達式中直接對變量進行操作,而不需要使用 $ 符號來引用變量值。

作用
  1. 執行算術運算let 可以對變量進行加、減、乘、除等基本運算。

  2. 更新變量值let 會根據運算結果更新變量的值。

  3. 支持復合運算符let 支持如 +=-=*=/= 等復合運算符

比較運算

比較運算有以下幾種類型

  • 用于條件測試
  • 用于for循環

用于條件測試的示例代碼如下

#!/bin/bashdeclare -i val=5   # 顯式聲明數值變量
num=2              # 隱式聲明數值變量# -eq:判斷val變量的值是否等于5
# []運算符用來執行條件測試表達式,其執行結果要么為真,要么為假
# []運算符和條件測試表達式之間前后有空格
if [ $val -eq 5 ]; thenecho "the value of val variable is 5"
fi# -ne:判斷num變量的值是否不等于5
# [[]]運算符用來執行條件測試表達式,其執行結果要么為真,要么為假
# [[]]運算符和條件測試表達式之間前后有空格
if [[ $num -ne 5 ]];thenecho "the value of num variable is not 5"
fi# -le:判斷num變量的值是否小于或等于val變量的值
# test命令關鍵字用來執行條件測試表達式,其執行結果要么為真,要么為假
if test $num -le $val ;thenecho "the value of num variable is lower or equal than val variable"
fi# -ge:判斷val變量的值是否大于或等于num變量的值
# [[]]運算符用來執行條件測試表達式,其執行結果要么為真,要么為假
# [[]]運算符和條件測試表達式之間前后有空格
if [[ $val -ge $num ]];thenecho "the value of val variable is growth or equal than num variable"
fi# -gt:判斷val變量的值是否大于5
# []運算符用來執行條件測試表達式,其執行結果要么為真,要么為假
# []運算符和條件測試表達式之間前后有空格
if [ $val -gt 5 ];thenecho "the value of val variable is growth than 5"
fi# -lt:判斷num變量的值是否小于5
# [[]]運算符用來執行條件測試表達式,其執行結果要么為真,要么為假
# [[]]運算符和條件測試表達式之間前后有空格
if [[ $num -lt 5 ]];thenecho "the value of num variable is lower than 5"
fi

gt 的作用是,greater than

大于的意思

then?的作用

  • 表示條件滿足后的執行起點:在 if 語句中,then 是一個分隔符,用于區分條件判斷部分和條件滿足時的執行部分。當條件表達式(如 [ $val -eq 5 ])的值為真(即條件滿足)時,then 后面的語句將被執行。

  • 語法結構的必要組成部分:在 Shell 腳本的 if 語句中,then 是必須的,它標志著條件判斷之后的代碼塊的開始。如果沒有 then,腳本將無法正確解析 if 語句的結構。

fi?的作用

  • 表示 if 語句的結束fiif 的反向拼寫,用于明確地標識 if 語句的結束。它告訴 Shell 解釋器,if 語句的邏輯已經完成,后續的代碼將不再屬于這個 if 語句的范圍。

  • 確保語法完整性和正確性:在 Shell 腳本中,if 語句必須以 fi 結尾,否則腳本會報錯。fi 是確保腳本語法完整性和正確性的關鍵部分。

val+num=7
val++: 5
val--: 6
++val: 6
--val: 5
val-num=3
val%num=1
var*num=10
val/num=2
var+=num:7
var-=num:5
val*=num:10
test.sh: line 37: let: val/=: syntax error: operand expected (error token is "/=")
val/=num:10
val%=num:0
[root@localhost ~]# vim test.sh
[root@localhost ~]# bash test.sh
val+num=7
val++: 5
val--: 6
++val: 6
--val: 5
val-num=3
val%num=1
var*num=10
val/num=2
var+=num:7
var-=num:5
val*=num:10
test.sh: line 37: let: val/=: syntax error: operand expected (error token is "/=")
the value of val variable is 5
the value of num variable is not 5
the value of num variable is lower or equal than val variable
the value of val variable is growth or equal than num variable
the value of num variable is lower than 5

用于用于for循環的示例代碼如下

#!/bin/bash# ==判斷變量i的值是否等于1
for ((i=1; i==1; i++));doecho $i
done# !=判斷變量i的值是否不等于3
for ((i=1; i!=3; i++)); doecho $i
done# <=判斷變量i的值是否小于等于4
for ((i=1; i<=4; i++)); doecho $i
done# >=判斷變量i的值是否大于等于1
for ((i=5; i>=1; i--));doecho $i
done# <判斷變量i的值是否小于7
# >判斷變量i的值是否大于0
# &&表示邏輯與
# ||表示邏輯或
# !表示邏輯非
# 非的優先級大于與,與的優先級大于或
for ((i=1; i>0 && i<7; i++)); doecho $i
done

運行結果為:

test.sh: line 1: 的值是否等于1: command not found
1
1
2
1
2
3
4
5
4
3
2
1
1
2
3
4
5
6

數組索引

數組是一種數據結構,也可以叫做數據序列,它是一段連續的內容空間,保存了連續的多個數據(數據類型可以不相同),可以使用數組index索引來訪問操作數組元素

根據數組index索引的不同可將數組分為

  • 普通數組:數組index索引為整數型
  • 關聯數組:數組index索引為字符串
普通數組

普通數組也可以稱為整型索引數組,它的聲明定義方式有以下幾種

#!/bin/bash# 使用declare -a顯式聲明變量數據類型為整型索引數組型
# 數組中各元素間使用空白字符分隔
# 字符串類型的元素使用引號
declare -a array1=(1 'b' 3 'a')
# 依次引用數組的第一、二、三、四個元素
# 不加下標時默認引用第一個元素
# 引用時必須加上{},否則$array1[0]的值為1[0]
echo "the first element of array1 is ${array1[0]}"
echo "the second element of array1 is ${array1[1]}"
echo "the third element of array1 is ${array1[2]}"
echo "the fourth element of array1 is ${array1[3]}"
# 查看數組所有元素
echo "all elements of array1 is ${array1[*]}"
echo "all elements of array1 is ${array1[@]}"# 由解釋器動態解釋變量數據類型為整型索引數組型
# 如果數組中各元素間使用逗號,則它們將作為一個整體,也就是數組索引0的值
array2=(1,'b',3,'a')
echo "the first element of array2 is ${array2[0]}"# 由解釋器動態解釋變量數據類型為整型索引數組型
# 數組元素使用自定義下標賦值
# 以下數組定義中,第一個元素是1,第二個元素是'b',第3個元素為空,第4個元素為'a'
array3=(1 'b' [3]='a')
# 依次引用數組的第一、二、三、四個元素
# 不加下標時默認引用第一個元素
echo "the first element of array3 is ${array3[0]}"
echo "the second element of array3 is ${array3[1]}"
echo "the third element of array3 is ${array3[2]}"
echo "the fourth element of array3 is ${array3[3]}"
# 查看數組中所有有效元素(不為空)的整型索引號
echo "the index of effective element is ${!array3[*]}"
echo "the index of effective element is ${!array3[@]}"
# 查看數組中的有效元素個數(只統計值不為空的元素)
echo "the num of array3 is ${#array3[*]}"
echo "the num of array3 is ${#array3[@]}"

結果為:

the first element of array1 is 1
the second element of array1 is b
the third element of array1 is 3
the fourth element of array1 is a
all elements of array1 is 1 b 3 a
all elements of array1 is 1 b 3 a
the first element of array2 is 1,b,3,a
the first element of array3 is 1
the second element of array3 is b
the third element of array3 is 
the fourth element of array3 is a
the index of effective element is 0 1 3
the index of effective element is 0 1 3
the num of array3 is 3
the num of array3 is 3

在 Bash 腳本中,${#array4[1]} 中的 # 符號的作用是獲取數組中指定元素的長度。

另外普通數組還支持以下運算操作

  • 返回數組長度(即有效元素的個數,不包括空元素)

    • ${#Array_Name[*]}
    • ${#Array_Name[@]}
  • 數組元素消除,該操作不會修改原數組元素,操作執行結果用數組來接收

    • Array_Name1=${Array_Name[*]#*word}:功能同下
    • Array_Name1=${Array_Name[*]##*word}:自左而右查找Array_Name數組中所有被匹配到的word匹配到的元素,并將所有匹配到的元素刪除(并不會刪除原數組中的元素),最后返回剩余的數組元素
    • Array_Name1=${Array_Name[*]%word*}:功能同下
    • Array_Name1=${Array_Name[*]%%word*}:自右而左查找Array_Name數組中所有被匹配到的word匹配到的元素,并將所有匹配到的元素刪除(并不會刪除原數組中的元素),最后返回剩余的數組元素
  • 數組元素提取,該操作不會修改原數組元素,操作執行結果用數組來接收

    • Array_Name1=${Array_Name[*]:offset}:返回Array_Name數組中索引為offset的數組元素以及后面所有元素;其中offset為整型數
    • Array_Name1=${Array_Name[*]:offset:length}:返回Array_Name數組中索引為offset的數值元素以及后面length-1個元素;其中offsetlength都為整型數

代碼示例如下

#!/bin/basharray_test=(/usr/bin /root/bin /usr/apache/bin /usr/mysql /usr/apache/bin)# 返回數組長度(即有效元素的個數,不包括空元素)
echo "the length of array_test is ${#array_test[*]}"
echo "the length of array_test is ${#array_test[@]}"# 數組元素消除,該操作不會修改原數組元素,操作執行結果用數組來接收
array_test1=${array_test[*]#*/usr/apache/bin}
echo "array_test:${array_test[*]}"
echo "array_test1:${array_test1[@]}"
array_test2=${array_test[*]##*/usr/apache/bin}
echo "array_test:${array_test[*]}"
echo "array_test2:${array_test2[@]}"
array_test3=${array_test[*]%/usr/apache/bin*}
echo "array_test:${array_test[*]}"
echo "array_test3:${array_test3[@]}"
array_test4=${array_test[*]%%/usr/apache/bin*}
echo "array_test:${array_test[*]}"
echo "array_test4:${array_test4[@]}"# 數組元素提取,該操作不會修改原數組元素,操作執行結果用數組來接收
array_test5=${array_test[*]:2}
echo "array_test:${array_test[*]}"
echo "array_test5:${array_test5[@]}"
array_test6=${array_test[*]:2:2}
echo "array_test:${array_test[*]}"
echo "array_test6:${array_test6[@]}"# 數組元素替換,該操作不會修改原數組元素,操作執行結果用數組來接收
array_test7=${array_test[*]/\/usr\/apache\/bin/}   # 需要用\對/進行轉義,替換值為空表示刪除前面匹配到的
echo "array_test:${array_test[*]}"
echo "array_test7:${array_test7[@]}"
array_test8=${array_test[*]//\/usr\/apache\/bin/}  # 需要用\對/進行轉義,替換值為空表示刪除前面匹配到的
echo "array_test:${array_test[*]}"
echo "array_test8:${array_test8[@]}"

執行結果如下

the length of array_test is 5
the length of array_test is 5
array_test:/usr/bin /root/bin /usr/apache/bin /usr/mysql /usr/apache/bin
array_test1:/usr/bin /root/bin /usr/mysql
array_test:/usr/bin /root/bin /usr/apache/bin /usr/mysql /usr/apache/bin
array_test2:/usr/bin /root/bin /usr/mysql
array_test:/usr/bin /root/bin /usr/apache/bin /usr/mysql /usr/apache/bin
array_test3:/usr/bin /root/bin /usr/mysql
array_test:/usr/bin /root/bin /usr/apache/bin /usr/mysql /usr/apache/bin
array_test4:/usr/bin /root/bin /usr/mysql
array_test:/usr/bin /root/bin /usr/apache/bin /usr/mysql /usr/apache/bin
array_test5:/usr/apache/bin /usr/mysql /usr/apache/bin
array_test:/usr/bin /root/bin /usr/apache/bin /usr/mysql /usr/apache/bin
array_test6:/usr/apache/bin /usr/mysql
array_test:/usr/bin /root/bin /usr/apache/bin /usr/mysql /usr/apache/bin
array_test7:/usr/bin /root/bin /usr/mysql
array_test:/usr/bin /root/bin /usr/apache/bin /usr/mysql /usr/apache/bin
array_test8:/usr/bin /root/bin /usr/mysql

同時普通數組也可用于for循環遍歷

代碼示例如下

#!/bin/bash# 獲取家目錄下文件列表,轉換成普通數組
array_test=(`ls ~`)
echo ${array_test[@]}
echo "----------------"# 以數組元素值的方式直接遍歷數組
for i in ${array_test[*]};doecho $i
done
echo "----------------"# 以數組index索引的方式遍歷數組
for i in ${!array_test[*]};doecho ${array_test[$i]}
done
echo "----------------"# 以數組元素個數的方式遍歷數組
for ((i=0;i<${#array_test[*]};i++));doecho ${array_test[$i]}
done

執行結果如下

anaconda-ks.cfg crontest.txt ln1 test.sh
----------------
anaconda-ks.cfg
crontest.txt
ln1
test.sh
----------------
anaconda-ks.cfg
crontest.txt
ln1
test.sh
----------------
anaconda-ks.cfg
crontest.txt
ln1
test.sh
關聯數組

關聯數組也可以稱為字符索引數組,它的聲明定義方式有以下幾種

#!/bin/bash# 聲明定義字符索引數組時必須使用declare -A
# 數組中各元素間使用空白字符分隔
declare -A array1=([name1]=jack [name2]=anony)
# 依次引用name1和name2對應的值
echo "the value of name1 element is ${array1[name1]}"
echo "the value of name2 element is ${array1[name2]}"# 聲明定義字符索引數組時必須使用declare -A
# 如果數組中各元素間使用逗號,則它們將作為一個整體
declare -A array2=([name1]=jack,[name2]=anony)
echo "the value of name1 element is ${array2[name1]}"
# 查看name1對應值的字符長度
echo "the length of name1 element is ${#array2[name1]}"# 聲明定義字符索引數組時必須使用declare -A
declare -A array3=([name1]=jack [name2]=anony)
echo "the value of name1 element is ${array3[name1]}"
echo "the value of name2 element is ${array3[name2]}"
# 通過字符索引進行賦值
array3[name3]=zhangsan
echo "the value of name3 element is ${array3[name3]}"
# 通過字符索引進行賦值
array3[name5]=lisi
# 查看數組所有元素
echo "the all effective element is ${array3[*]}"
echo "the all effective element is ${array3[@]}"
# 查看數組中所有有效元素(不為空)的字符索引號,默認是對應值的排列順序
echo "the index of all effective element is ${!array3[*]}"
echo "the index of all effective element is ${!array3[@]}"
# 查看數組中的有效元素個數(只統計值不為空的元素)
echo "the length of array is ${#array3[*]}"
echo "the length of array is ${#array3[@]}"

執行結果如下

the value of name1 element is jack
the value of name2 element is anony
the value of name1 element is jack,[name2]=anony
the length of name1 element is 18
the value of name1 element is jack
the value of name2 element is anony
the value of name3 element is zhangsan
the all effective element is zhangsan anony jack lisi
the all effective element is zhangsan anony jack lisi
the index of all effective element is name3 name2 name1 name5
the index of all effective element is name3 name2 name1 name5
the length of array is 4
the length of array is 4

和普通數組一樣,關聯數組也支持以下運算操作

  • 返回數組長度(即有效元素的個數,不包括空元素)

    • ${#Array_Name[*]}
    • ${#Array_Name[@]}
  • 數組元素消除,該操作不會修改原數組元素,操作執行結果用數組來接收

    • declare?-A?Array_Name1=${Array_Name[*]#*word}:功能同下
    • declare?-A?Array_Name1=${Array_Name[*]##*word}:自左而右查找Array_Name數組中所有被匹配到的word匹配到的元素,并將所有匹配到的元素刪除(并不會刪除原數組中的元素),最后返回剩余的數組元素
    • declare?-A?Array_Name1=${Array_Name[*]%word*}:功能同下
    • declare?-A?Array_Name1=${Array_Name[*]%%word*}:自右而左查找Array_Name數組中所有被匹配到的word匹配到的元素,并將所有匹配到的元素刪除(并不會刪除原數組中的元素),最后返回剩余的數組元素
  • 數組元素提取,該操作不會修改原數組元素,操作執行結果用數組來接收

    • declare?-A?Array_Name1=${Array_Name[*]:offset}:返回Array_Name數組中索引為offset的數組元素以及后面所有元素;其中offset為整型數
    • declare?-A?Array_Name1=${Array_Name[*]:offset:length}:返回Array_Name數組中索引為offset的數值元素以及后面length-1個元素;其中offsetlength都為整型數
#!/bin/bashdeclare -A array_test=([ele1]=/usr/bin [ele2]=/root/bin [ele3]=/usr/apache/bin [ele4]=/usr/mysql [ele5]=/usr/apache/bin)# 返回數組長度(即有效元素的個數,不包括空元素)
echo "the length of array_test is ${#array_test[*]}"
echo "the length of array_test is ${#array_test[@]}"# 數組元素消除,該操作不會修改原數組元素,操作執行結果用數組來接收
declare -A array_test1=${array_test[*]#*/usr/apache/bin}
echo "array_test:${array_test[*]}"
echo "array_test1:${array_test1[@]}"
declare -A array_test2=${array_test[*]##*/usr/apache/bin}
echo "array_test:${array_test[*]}"
echo "array_test2:${array_test2[@]}"
declare -A array_test3=${array_test[*]%/usr/apache/bin*}
echo "array_test:${array_test[*]}"
echo "array_test3:${array_test3[@]}"
declare -A array_test4=${array_test[*]%%/usr/apache/bin*}
echo "array_test:${array_test[*]}"
echo "array_test4:${array_test4[@]}"# 數組元素提取,該操作不會修改原數組元素,操作執行結果用數組來接收
declare -A array_test5=${array_test[*]:2}
echo "array_test:${array_test[*]}"
echo "array_test5:${array_test5[@]}"
declare -A array_test6=${array_test[*]:2:2}
echo "array_test:${array_test[*]}"
echo "array_test6:${array_test6[@]}"# 數組元素替換,該操作不會修改原數組元素,操作執行結果用數組來接收
declare -A array_test7=${array_test[*]/\/usr\/apache\/bin/}
echo "array_test:${array_test[*]}"
echo "array_test7:${array_test7[@]}"
declare -A array_test8=${array_test[*]//\/usr\/apache\/bin/}
echo "array_test:${array_test[*]}"
echo "array_test8:${array_test8[@]}"

執行結果如下

the length of array_test is 5
the length of array_test is 5
array_test:/usr/mysql /usr/apache/bin /usr/bin /root/bin /usr/apache/bin
array_test1:/usr/mysql  /usr/bin /root/bin 
array_test:/usr/mysql /usr/apache/bin /usr/bin /root/bin /usr/apache/bin
array_test2:/usr/mysql  /usr/bin /root/bin 
array_test:/usr/mysql /usr/apache/bin /usr/bin /root/bin /usr/apache/bin
array_test3:/usr/mysql  /usr/bin /root/bin 
array_test:/usr/mysql /usr/apache/bin /usr/bin /root/bin /usr/apache/bin
array_test4:/usr/mysql  /usr/bin /root/bin 
array_test:/usr/mysql /usr/apache/bin /usr/bin /root/bin /usr/apache/bin
array_test5:/usr/apache/bin /usr/bin /root/bin /usr/apache/bin
array_test:/usr/mysql /usr/apache/bin /usr/bin /root/bin /usr/apache/bin
array_test6:/usr/apache/bin /usr/bin
array_test:/usr/mysql /usr/apache/bin /usr/bin /root/bin /usr/apache/bin
array_test7:/usr/mysql  /usr/bin /root/bin 
array_test:/usr/mysql /usr/apache/bin /usr/bin /root/bin /usr/apache/bin
array_test8:/usr/mysql  /usr/bin /root/bin

關聯數組和普通數組一樣,也可用于for循環遍歷

先創建test.log文件,內容如下

[root@localhost ~]# cat test.log
portmapper
portmapper
portmapper
portmapper
portmapper
portmapper
status
status
mountd
mountd
mountd
mountd
mountd
mountd
nfs
nfs
nfs_acl
nfs
nfs
nfs_acl
nlockmgr
nlockmgr
nlockmgr
nlockmgr
nlockmgr
nlockmgr

代碼示例如下:統計文件中重復行的次數

#!/bin/bashdeclare -A array_testfor i in `cat ~/test.log`;dolet ++array_test[$i]  # 修改數組元素值
donefor j in ${!array_test[*]};doprintf "%-15s %3s\n" $j :${array_test[$j]}
done

執行結果如下

status           :2
nfs              :4
portmapper       :6
nlockmgr         :6
nfs_acl          :2
mountd           :6

列表型

列表型變量常用來for循環遍歷,但是一般是在for循環中直接使用,當然也可以通過變量進行引用

代碼示例如下

#!/bin/bash# 生成數字列表:使用{}運算符
for i in {1..4};doecho $i
done
echo "-------------------"# 生成數字列表:使用seq命令
for i in `seq 1 2 7`;doecho $i
done
echo "-------------------"# 生成文件列表:直接給出列表
for fileName in /etc/init.d/functions /etc/rc.d/rc.sysinit /etc/fstab;doecho $fileName
done
echo "-------------------"# 生成文件列表:使用文件名通配機制生成列表
dirName=/etc/rc.d
for fileName in $dirName/*.d;doecho $fileName
done
echo "-------------------"# 生成文件列表:使用``運算符引用相關命令的執行結果
for fileName in `ls ~`;doecho $fileName
done

代碼執行結果

1
2
3
4
-------------------
1
3
5
7
-------------------
/etc/init.d/functions
/etc/rc.d/rc.sysinit
/etc/fstab
-------------------
/etc/rc.d/init.d
/etc/rc.d/rc0.d
/etc/rc.d/rc1.d
/etc/rc.d/rc2.d
/etc/rc.d/rc3.d
/etc/rc.d/rc4.d
/etc/rc.d/rc5.d
/etc/rc.d/rc6.d
-------------------
anaconda-ks.cfg
crontest.txt
ln1
test.log
test.sh

字符串型

首先我們來聲明定義一個字符串型變量:Var_Name="anony"

  • 在bash中,變量默認都是字符串類型,也都是以字符串方式存儲,所以字符串可以不需要使用"",除非特殊聲明,否則都會解釋成字符串
  • 該種方式聲明,變量默認是本地全局變量,可以通過local?Var_Name關鍵字將變量修改為局部變量,可以通過export?Var_Name關鍵字將變量導出為環境變量
  • 該種聲明定義方式是由shell解釋器動態執行隱式聲明該變量數據類型為字符串型

字符串型變量一般支持以下運算操作

  • 返回字符串長度:${#Var_Name}(長度包括空白字符)

  • 字符串消除

    • ${var#*word}:查找var中自左而右第一個被word匹配到的串,并將此串及向左的所有內容都刪除;此處為非貪婪匹配
    • ${var##*word}:查找var中自左而右最后一個被word匹配到的串,并將此串及向左的所有內容都刪除;此處為貪婪匹配
    • ${var%word*}:查找var中自右而左第一個被word匹配到的串,并將此串及向右的所有內容都刪除;此處為非貪婪匹配
    • ${var%%word*}:查找var中自右而左最后一個被word匹配到的串,并將此串及向右的所有內容都刪除;此處為貪婪匹配
  • 字符串提取

    • ${var:offset}:自左向右偏移offset個字符,取余下的字串;例如:name=jerry,${name:2}結果為rry
    • ${var:offset:length}:自左向右偏移offset個字符,取余下的length個字符長度的字串。例如:``name=’hello world’ ${name:2:5}結果為llo w``

函數

在編程語言中,函數是能夠實現模塊化編程的工具,每個函數都是一個功能組件,但是函數必須被調用才能執行

函數存在的主要作用在于:最大化代碼重用,最小化代碼冗余

在shell中,函數可以被當做命令一樣執行,它的本質是命令的組合結構體,即可以將函數看成一個普通命令或一個小型腳本。接下來本章內容將從以下幾個方面來介紹函數

  • 函數定義
  • 函數調用
  • 函數退出
  • 示例代碼

0x00 函數定義

在shell中函數定義的方法有兩種(使用help?function命令可以查看)

# 方法一
function FuncName {COMMANDS_LIST
} [&>/dev/null]# 方法二
FuncName() {COMMANDS_LIST
} [&>/dev/null]

上面兩種函數定義方法定義了一個名為FuncName的函數

  • 方法一中:使用了function關鍵字,此時函數名FuncName后面的括號可以省略
  • 方法二中:省略了function關鍵字,此時函數名FuncName后面的括號不能省略

COMMANDS_LIST是函數體,它與以下特點

  • 函數體通常使用大括號{}包圍,由于歷史原因,在shell中大括號本身也是關鍵字,所以為了不產生歧義,函數體和大括號之間必須使用空格、制表符、換行符分隔開來;一般我們都是通過換行符進行分隔
  • 函數體中的每一個命令必須使用;換行符進行分隔;如果使用&結束某條命令,則表示該條命令會放入后臺執行

需要注意的是

  • &>/dev/null表示將函數體執行過程中可能輸出的信息重定向至/dev/null中,該功能可選
  • 定義函數時,還可以指定可選的函數重定向功能,這樣當函數被調用的時候,指定的重定向也會被執行
  • 當前shell定義的函數只能在當前shell使用,子shell無法繼承父shell的函數定義,除非使用export?-f將函數導出為全局函數;如果想取消函數的導出可以使用export?-n
  • 定義了函數后,可以使用unset?-f移除當前shell中已定義的函數
  • 可以使用typeset?-f?[func_name]declare?-f?[func_name]查看當前shell已定義的函數名和對應的定義語句;使用typeset?-Fdeclare?-F則只顯示當前shell中已定義的函數名
  • 只有先定義了函數,才可以調用函數;不允許函數調用語句在函數定義語句之前
  • 在shell腳本中,函數沒有形參的概念,使用方法二定義函數時,括號里什么都不用寫,只需要在函數體內使用相關的調用機制調用接收參數即可

0x01 函數調用

函數的調用格式如下

FuncName ARGS_LIST

其中

  • FuncName:表示被調用函數的函數名,需要注意的是在shell中函數調用時函數名后面沒有()操作符
  • ARGS_LIST:表示被調用函數的傳入參數,在shell中給函數傳入參數和腳本接收參數的方法相似,直接在函數名后面加上需要傳入的參數即可

函數調用時需要注意以下幾點

  • 如果函數名和命令名相同,則優先執行函數,除非使用command命令。例如:定義了一個名為rm的函數,在bash中輸入rm執行時,執行的是rm函數,而非/bin/rm命令,除非使用command?rm?ARGS,表示執行的是/bin/rm命令
  • 如果函數名和命令別名相同,則優先執行命令別名,即在優先級方面:別名別名>函數>命令自身

當函數調用函數被執行時,它的執行邏輯如下

  • 接收參數:shell函數也接受位置參數變量,但函數的位置參數是調用函數時傳遞給函數的,而非傳遞給腳本的參數,所以腳本的位置變量和函數的位置變量是不同的;同時shell函數也接收特殊變量。函數體內引用位置參數和特殊變量方式如下

    • 位置參數

      • $0:和腳本位置參數一樣,引用腳本名稱
      • $1:引用函數的第1個傳入參數
      • $n:引用函數的第n個傳入參數
    • 特殊變量

      • $?:引用上一條命令的執行狀態返回值,狀態用數字表示0-255

        • 0:表示成功
        • 1-255:表示失敗;其中1/2/127/255是系統預留的,寫腳本時要避開與這些值重復
      • $$:引用當前shell的PID。除了執行bash命令和shell腳本時,$$不會繼承父shell的值,其他類型的子shell都繼承

      • $!:引用最近一次執行的后臺進程PID,即運行于后臺的最后一個作業的PID

      • $#:引用函數所有位置參數的個數

      • $*:引用函數所有位置參數的整體,即所有參數被當做一個字符串

      • $@:引用函數所有單個位置參數,即每個參數都是一個獨立的字符串

  • 執行函數體:在函數體執行時,需要注意的是

    • 函數內部引用變量的查找次序:內層函數自己的變量>外層函數的變量>主程序的變量>bash內置的環境變量

    • 函數內部引用變量的作用域

      • 本地變量:函數體引用本地變量時,重新賦值會覆蓋原來的值,如果不想覆蓋值,可以使用local進行修飾
      • 局部變量:函數體引用局部變量時,函數退出,將會被撤銷
      • 環境變量:函數體引用環境變量時,重新賦值會覆蓋原來的值,如果不想覆蓋值,可以使用local進行修飾
      • 位置變量:函數體引用位置變量表示引用傳遞給函數的參數
      • 特殊變量
  • 函數返回:函數返回值可分為兩類

    • 執行結果返回值:正常的執行結果返回值有以下幾種

      • 函數中的打印語句:如echoprint
      • 最后一條命令語句的執行結果值
    • 執行狀態返回值:執行狀態返回值主要有以下幾種

      • 使用return語句自定義返回值,即return n,n表示函數的退出狀態碼,不給定狀態碼時默認狀態碼為0
      • 取決于函數體中最后一條命令語句的執行狀態返回值

在shell中不僅可以調用本腳本文件中定義的函數,還可以調用其它腳本文件中定義的函數

  • 先使用.?/path/to/shellscriptsource?/path/to/shellscript命令導入指定的腳本文件
  • 然后使用相應的函數名調用函數即可

0x02 函數退出命令

函數退出命令有

  • return?[n]:可以在函數體內的任何地方使用,表示退出整個函數;數值n表示函數的退出狀態碼
  • exit?[n]:可以在腳本的任何地方使用,表示退出整個腳本;數值n表示腳本的退出狀態碼

此處需要注意的是:return并非只能用于function內部

  • 如果returnfunction之外,但在.或者source命令的執行過程中,則直接停止該執行操作,并返回給定狀態碼n(如果未給定,則為0)
  • 如果returnfunction之外,且不在source.的執行過程中,則這將是一個錯誤用法

可能有些人不理解為什么不直接使用exit來替代這時候的return。下面給個例子就能清楚地區分它們

先創建一個腳本文件proxy.sh,內容如下,用于根據情況設置代理的環境變量

#!/bin/bashproxy="http://127.0.0.1:8118"
function exp_proxy() {export http_proxy=$proxyexport https_proxy=$proxyexport ftp_proxy=$proxyexport no_proxy=localhost
}case $1 inset) exp_proxy;;unset) unset http_proxy https_proxy ftp_proxy no_proxy;;*) return 0
esac

首先我們來了解下source的特性:即source是在當前shell而非子shell執行指定腳本中的代碼

當進入bash

  • 需要設置環境變量時:使用source?proxy.sh?set即可
  • 需要取消環境變量時:使用source?proxy.sh?unset即可

此時如果不清楚該腳本的用途或者一時手快直接輸入source?proxy.sh,就可以區分exitreturn

  • 如果上述腳本是return?0,那么表示直接退出腳本而已,不會退出bash
  • 如果上述腳本是exit?0,則表示退出當前bash,因為source是在當前shell而非子shell執行指定腳本中的代碼

可能你想象不出在source執行中的return有何用處:從source來考慮,它除了用在某些腳本中加載其他環境,更主要的是在bash環境初始化腳本中使用,例如/etc/profile~/.bashrc等,如果你在/etc/profile中用exit來替代function外面return,那么永遠也登陸不上bash

0x03 示例代碼

  • 隨機生成密碼
#!/bin/bashgenpasswd(){local l=$1[ "$l" == ""  ]&& l=20tr -dc A-Za-z0-9_</dev/urandom | head -c ${l} | xargs
}genpasswd $1   # 將腳本傳入的位置參數傳遞給函數,表示生成的隨機密碼的位數
  • 寫一個腳本,完成如下功能:

    • 1、腳本使用格式:mkscript.sh?[-D|--description?"script?description"]?[-A|--author?"script?author"]?/path/to/somefile

    • 2、如果文件事先不存在,則創建;且前幾行內容如下所示:

      • #!/bin/bash
      • # Description: script description
      • # Author: script author
    • 3、如果事先存在,但不空,且第一行不是#!/bin/bash,則提示錯誤并退出;如果第一行是#!/bin/bash,則使用vim打開腳本;把光標直接定位至最后一行

    • 4、打開腳本后關閉時判斷腳本是否有語法錯誤;如果有,提示輸入y繼續編輯,輸入n放棄并退出;如果沒有,則給此文件以執行權限

#!/bin/bash
read -p "Enter a file: " filename
declare authname
declare descroptions(){
if [[ $# -ge 0 ]];thencase $1 in-D|--description)authname=$4descr=$2;;-A|--author)descr=$4authname=$2;;esac
fi
}command(){
if  bash -n $filename &> /dev/null;thenchmod +x $filename
elsewhile true;doread -p "[y|n]:" optioncase $option iny)vim + $filename;;n)exit 8;;esacdone
fi
exit 6
}oneline(){
if [[ -f $filename ]];thenif [ `head -1 $filename` == "#!/bin/bash" ];thenvim + $filenameelseecho "wrong..."exit 4fi
elsetouch $filename && echo -e "#!/bin/bash\n# Description: $descr\n# Author: $authname" > $filenamevim + $filename
fi
command
}options $*
oneline
  • 寫一個腳本,完成如下功能:

    • 1、提示用戶輸入一個可執行命令
    • 2、獲取這個命令所依賴的所有庫文件(使用ldd命令)
    • 3、復制命令至/mnt/sysroot/對應的目錄中;如果復制的是cat命令,其可執行程序的路徑是/bin/cat,那么就要將/bin/cat復制到/mnt/sysroot/bin/目錄中,如果復制的是useradd命令,而useradd的可執行文件路徑為/usr/sbin/useradd,那么就要將其復制到/mnt/sysroot/usr/sbin/目錄中
    • 4、復制各庫文件至/mnt/sysroot/對應的目錄中
#!/bin/bashoptions(){for i in $*;dodirname=`dirname $i`[ -d /mnt/sysroot$dirname ] || mkdir -p /mnt/sysroot$dirname[ -f /mnt/sysroot$i ]||cp $i /mnt/sysroot$dirname/done
}while true;doread -p "Enter a command : " pidname[[ "$pidname" == "quit" ]] && echo "Quit " && exit 0bash=`which --skip-alias $pidname`if [[ -x $bash ]];thenoptions `/usr/bin/ldd $bash |grep -o "/[^[:space:]]\{1,\}"`options $bashelseecho "PLZ a command!"fi
done# 說明
# 將bash命令的相關bin文件和lib文件復制到/mnt/sysroot/目錄中后
# 使用chroot命令可切換根目錄,切換到/mnt/sysroot/后可當做bash執行復制到該處的命令,作為bash中的bash
  • 寫一個腳本,用來判定172.16.0.0網絡內有哪些主機在線,在線的用綠色顯示,不在線的用紅色顯示
#!/bin/bash
Cnetping(){for i in {1..254};doping -c 1 -w 1 $1.$iif [[ $? -eq 0 ]];thenecho -e -n "\033[32mping 172.16.$i.$j ke da !\033[0m\n"elseecho -e -n "\033[31mping 172.16.$i.$j bu ke da !\033[0m \n"fidone
}Bnetping(){for j in {0..255};doCnetping $1.$jdone
}Bnetping 172.16
  • 寫一個腳本,用來判定隨意輸入的ip地址所在網段內有哪些主機在線,在線的用綠色顯示,不在線的用紅色顯示
#!/bin/bash
Cnetping(){for i in {1..254};doping -c 1 -w 1 $1.$iif [[ $? -eq 0 ]];thenecho -e -n "\033[32mping 172.16.$i.$j ke da !\033[0m\n"elseecho -e -n "\033[31mping 172.16.$i.$j bu ke da !\033[0m \n"fidone
}Bnetping(){for j in {0..255};doCnetping $1.$jdone
}Anetping(){for m in {0.255};doBnetping $1.$mdone
}netType=`echo $1 | cut -d'.' -f1`if [ $netType -gt 0 -a $netType -le 126 ];thenAnetping $1
elif [ $netType -ge 128 -a $netType -le 191 ];thenBnetping $1
elif [ $netType -ge 192 -a $netType -le 223 ];thenCnetping $1
elseecho "Wrong"exit 3
fi

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/79235.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/79235.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/79235.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

你了解哪些Java限流算法?

大家好&#xff0c;我是鋒哥。今天分享關于【你了解哪些Java限流算法?】面試題。希望對大家有幫助&#xff1b; 你了解哪些Java限流算法? 1000道 互聯網大廠Java工程師 精選面試題-Java資源分享網 在 Java 中&#xff0c;限流算法廣泛用于控制流量、避免過載和保護系統的穩…

prime-2 靶場筆記(vuInhub靶場)

前言&#xff1a; 在本次靶場環境中涉及的知識點&#xff0c;主要包含LFI和SMB以及Lxd組提權&#xff0c;具體內容包括主機探測、端口掃描、目錄掃描、wpscan掃描、反彈shell、一句話木馬、容器、linux各種提權和維持。 環境介紹&#xff1a; 本靶場使用了kali&#xff08;192…

SparseDrive---論文閱讀

純視覺下的稀疏場景表示 算法動機&開創性思路 算法動機&#xff1a; 依賴于計算成本高昂的鳥瞰圖&#xff08;BEV&#xff09;特征表示。預測和規劃的設計過于直接&#xff0c;沒有充分利用周圍代理和自我車輛之間的高階和雙向交互。場景信息是在agent周圍提取&#xff…

旅游特種兵迪士尼大作戰:DeepSeek高精準路徑優化

DeepSeek大模型高性能核心技術與多模態融合開發 - 商品搜索 - 京東 隨著假期的腳步日漸臨近&#xff0c;環球影城等備受矚目的主題游樂場&#xff0c;已然成為大人與孩子們心中不可或缺的節日狂歡圣地。然而&#xff0c;隨之而來的龐大客流&#xff0c;卻總讓無數游客在歡樂的…

android rtsp 拉流h264 h265,解碼nv12轉碼nv21耗時卡頓問題及ffmpeg優化

一、 背景介紹及問題概述 項目需求需要在rk3568開發板上面&#xff0c;通過rtsp協議拉流的形式獲取攝像頭預覽&#xff0c;然后進行人臉識別 姿態識別等后續其它操作。由于rtsp協議一般使用h.264 h265視頻編碼格式&#xff08;也叫 AVC 和 HEVC&#xff09;是不能直接用于后續處…

運維面試題(十四)

6.將日志從一臺服務器保存到另一臺服務器中的方法 1.使用 rsync 同步日志文件 2.使用 scp 手動或腳本化傳輸 3.配置日志服務&#xff08;如 syslog 或 rsyslog &#xff09;遠程傳輸 ? 4.編寫腳本定時上傳&#xff1a;結合 cron 定時任務和傳輸工具&#xff0c;編…

永磁同步電機控制中,滑模觀測器是基于反電動勢觀測轉子速度和角度的?擴展卡爾曼濾波觀測器是基于什么觀測的?擴展卡爾曼濾波觀測器也是基于反電動勢嗎?

滑模觀測器在PMSM中的應用&#xff1a; 滑模觀測器是一種非線性觀測器&#xff0c;利用切換函數設計&#xff0c;使得狀態估計誤差迅速趨近于零&#xff0c;實現快速響應和對外部干擾的魯棒性。 在永磁同步電機&#xff08;PMSM&#xff09;無傳感器控制中&#xff0c;滑模觀測…

【前端】Vue一本通 ESLint JSX

近幾天更新完畢&#xff0c;不定期持續更新&#xff0c;建議關注收藏點贊。 目錄 工具推薦vscode插件vue-devtoolsESLint JSX語法擴展簡介設計模式快速入門 vue/cli腳手架使用vue指令 工具推薦 工欲善其事&#xff0c;必先利其器。 vscode插件 Vetur&#xff1a;vue代碼高亮…

【adb】bat批處理+adb 自動亮屏,自動解鎖屏幕,啟動王者榮耀

準備adb 下載 需要確認是否安裝了adb.exe文件,可以在: 任務管理器 -->詳細信息–>找一下后臺運行的adb 安裝過anroid模擬器,也存在adb,例如:雷電安裝目錄 D:\leidian\LDPlayer9 單獨下載adb 官方下載地址:[官方網址] 下載目錄文件: 測試adb USB連接手機 首先在設置界…

微信小程序轉為App實踐篇 FinClip

參考下面鏈接先 開始實踐 微信小程序轉為App并上架應用市場_微信小程序生成app-CSDN博客 首先在FinClip 官網上下載應用 小程序開發工具下載_小程序sdk下載資源-FinClip資源下載|泰坪小程序開放平臺 下載到本地安裝 打開導入自己的小程序項目&#xff1b;導入時會解析自己的…

arco design框架中的樹形表格使用中的緩存問題

目錄 1.問題 2.解決方案 1.問題 arco design框架中的樹形表格使用中的緩存問題&#xff0c;使用了樹形表格的load-more懶加載 點擊展開按鈕后&#xff0c;點擊關閉&#xff0c;再次點擊展開按鈕時&#xff0c;沒有調用查詢接口&#xff0c;而是使用了緩存的數據。 2.解決方…

100個GEO基因表達芯片或轉錄組數據處理023.GSE24807

100個GEO基因表達芯片或轉錄組數據處理 寫在前邊 雖然現在是高通量測序的時代&#xff0c;但是GEO、ArrayExpress等數據庫儲存并公開大量的基因表達芯片數據&#xff0c;還是會有大量的需求去處理芯片數據&#xff0c;并且建模或驗證自己所研究基因的表達情況&#xff0c;芯片…

SAP ECCS標準報表在報表中不存在特征CG細分期間 消息號 GK715報錯分析

ECCS報表執行報錯&#xff1a; 在報表中不存在特征CG細分期間 消息號 GK715 診斷 未在報表中指定特征CG細分期間。但是&#xff0c;同時需要特征CG細分期間和其它特征。例如&#xff1a; 期間’需要用于擴展合并組。 系統響應 處理終止 步驟 調整報表定義。 報這個錯。 業務背景…

spring boot 文件下載

1.添加文件下載工具依賴 Commons IO is a library of utilities to assist with developing IO functionality. <dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.6</version> </depe…

FastAPI 中定義接口函數參數,包含請求體參數、查詢參數、依賴注入參數的組合

FastAPI 中定義接口函數參數&#xff0c;包含請求體參數、查詢參數、依賴注入參數的組合。 ? 示例結構 async def chat(request: Request,data: ChatData,conversation_id: Optional[str] Query(None),current_user: User Depends(get_current_user), ):這表示你定義了一個…

實用類題目

1. 密碼強度檢測 題目描述&#xff1a;生活中&#xff0c;為保證賬戶安全&#xff0c;密碼需要有一定強度。編寫一個方法&#xff0c;接收一個字符串作為密碼&#xff0c;判斷其是否符合以下強度要求&#xff1a;長度至少為 8 位&#xff0c;包含至少一個大寫字母、一個小寫字…

MATLAB學習筆記(二) 控制工程會用到的

MATLAB中 控制工程會用到的 基礎傳遞函數表達傳遞函數 零極點式 狀態空間表達式 相互轉化畫響應圖線根軌跡Nyquist圖和bode圖現控部分求約旦判能控能觀極點配置和狀態觀測 基礎 傳遞函數表達 % 拉普拉斯變換 syms t s a f exp(a*t) %e的a次方 l laplace(f) …

基于YOLOv9的課堂行為檢測系統

基于YOLOv9的課堂行為檢測系統 項目概述 本項目是一個基于YOLOv9深度學習模型的課堂行為檢測系統&#xff0c;旨在通過計算機視覺技術自動識別和監測課堂中學生的各種行為狀態&#xff0c;幫助教師更好地了解課堂教學效果。 項目結構 課堂行為檢測/ ├── data/ │ ├──…

C 語言中的 volatile 關鍵字

1、概念 volatile 是 C/C 語言中的一個類型修飾符&#xff0c;用于告知編譯器&#xff1a;該變量的值可能會在程序控制流之外被意外修改&#xff08;如硬件寄存器、多線程共享變量或信號處理函數等&#xff09;&#xff0c;因此編譯器不應對其進行激進的優化&#xff08;如緩存…

java 洛谷題單【算法2-1】前綴和、差分與離散化

P8218 【深進1.例1】求區間和 解題思路 前綴和數組&#xff1a; prefixSum[i] 表示數組 a 的前 (i) 項的和。通過 prefixSum[r] - prefixSum[l - 1] 可以快速計算區間 ([l, r]) 的和。 時間復雜度&#xff1a; 構建前綴和數組的時間復雜度是 (O(n))。每次查詢的時間復雜度是 …