目錄
- shell編程入坑2
- shell內置命令與外置命令
- bash部分基礎命令
- shell子串的一些用法
- 計算變數長度的各種方式
- 資料計算的命令
- 條件判斷
- 基本語法
- 常用判斷條件
- 流程控制
- if
- case
- for
- while
- read 命令詳解
- 函式
- 系統函式
- basename
- dirname
- date
- 自定義函式
- 系統函式
shell編程入坑2
shell內置命令與外置命令
內置命令:在系統啟動時加載到記憶體中,常駐記憶體,執行效率更高,但是占用資源,
內置命令相當于是shell的一部分,不需要單獨去讀取某個檔案,系統啟動后,就執行在記憶體中了,
- 使用
type 命令可以查看一個命令是否是內置還是外置命令:
┌──(kali?kali)-[~/桌面]
└─$ type cd
cd 是 shell 內建
- 使用
compgen -b可以查看linux所有內置的命令,
外置命令:系統需要從硬碟中讀取程式檔案,再讀入記憶體加載,
外置命令是存在于shell之外的程式,外部命令程式通常位于
/bin,/usr/bin,/sbin或/usr/sbin中,
使用which可以查看命令的位置
┌──(kali?kali)-[~/桌面]
└─$ which ps
/usr/bin/ps
┌──(kali?kali)-[~/桌面]
└─$ type ps
ps 是 /usr/bin/ps # 說明ps是外置命令
當外部命令執行時,父行程會衍生一個子行程,由該子行程執行該外部命令,比如下面執行ps -f --forest,可以看出ps -f --forest執行時PID為107548,而其PPID為15837,也正是zsh shell的PID,說明這一程序中,shell衍生了子行程來執行ps -f --forest,
UID PID PPID C STIME TTY TIME CMD
kali 15837 15831 0 19:00 pts/0 00:00:00 /usr/bin/zsh
kali 107548 15837 0 22:54 pts/0 00:00:00 \_ ps -f --forest
bash部分基礎命令
- 內置
echo
作用:向視窗輸出命令,結尾默認輸出換行
兩個重要引數
| 引數 | 意義 |
|---|---|
| -e | 輸出時決議字串中的特殊符號 |
| -n | 不換行輸出 |
┌──(root?kali)-[/home/kali/桌面]
└─# echo -n "123456"
123456
┌──(root?kali)-[/home/kali/桌面]
└─# echo -n "123456";echo -n "123456"
123456123456
┌──(root?kali)-[/home/kali/桌面]
└─# echo "123\n456"
123\n456
┌──(root?kali)-[/home/kali/桌面]
└─# echo -e "123\n456"
123
456
printf
作用:和echo類似,也是向視窗輸出指定文本,具體語法與C語言中的printf輸出函式類似,
用法:
└─# printf
printf:用法:printf [-v var] 格式 [引數]
└─# name="j";age=31;printf "my name is %s;\n my age is %d" $name $age
my name is j;
my age is 31
eval
作用:可以執行多個命令
└─# eval ls;pwd
1 引數傳遞.sh haha hahar hello.txt test.sh tmux.txt
/home/kali/桌面
其實發現,也可以不加eval直接運行命令,
exec
作用:不創建子行程,執行后續命令,且執行完畢后,自動exit
┌─(root?kali)-[/home/kali/桌面]
└─# useradd jackie
┌──(root?kali)-[/home/kali/桌面]
└─# su jackie # 進入其他用戶的行程
$ exec date
2022年 08月 31日 星期三 18:30:36 CST
# 使用exec運行date命令后,可以發現退出了當前用戶的shell行程
┌──(root?kali)-[/home/kali/桌面]
└─#
read
作用:一個一個詞組地接收輸入的引數,每個詞組需要使用空格進行分隔;如果輸入的詞組個數大于需要的引數個數,則多出的詞組將被作為整體為最后一個引數接收,
read.sh內容如下:
#! /bin/bash
read first second
echo "接受的第一個引數為:$first,第二個引數為:$second"
執行:
┌──(kali?kali)-[~/桌面]
└─$ ./read.sh
a b c d
接受的第一個引數為:a,第二個引數為:b c d
- 外置
expr
作用:一般用于整數值計算,但也可用于字串操作,
使用格式:expr argument operator argument
? 引數說明:argument:為第一個引數
? operator:為操作運算子
? argument:為第二個引數
# 普通數值計算,需注意運算子左右要留空格,計算的數值要為整數
expr 10 + 20
30
expr 10 - 20
-10
# *號在shell中有其他特殊的含義,如果要計算乘法,使用\將其轉義.
expr 5 \* 2
10
# 用于字串操作,如計算字串長度
expr length "abcd"
4
shell子串的一些用法
部分相關特殊用法:
注:x為一個字串的變數名,下標從0開始,支持通配符,
| 符號 | 含義 |
|---|---|
| ${x}或$x | 回傳變數x的值 |
| ${#x} | 回傳變數值的長度,即字符長度 |
| ${x:start} | 回傳變數x中從第start個字符開始,到最后的部分,需要注意的是:start的取值在0到${#var}-1之間 |
| ${x:start:len} | 回傳變數x中從第start個字符開始長度為len的部分 |
| ${x#word} | 從開頭洗掉最短匹配的子串 |
| ${x##word} | 從開頭洗掉最長匹配的子串 |
| ${x%word} | 從結尾洗掉最短匹配的子串 |
| ${x%%word} | 從結尾洗掉最長匹配的子串 |
| ${x/pattern/string} | 用string代替第一個匹配的pattern |
| ${x//pattern/string} | 用string代替所有的pattern |
| ${parameter:-word} | 如果parameter變數值為空,回傳word字串 |
| ${parameter:=word} | 如果parameter變數值為空,則word替代變數值,且回傳其值 |
| ${parameter:?word} | 如果parameter變數值為空,word當作stderr輸出,否則輸出變數值,用于設定變數為空導致錯誤時,回傳的錯誤資訊 |
| ${parameter:+word} | 如果parameter變數為空,什么都不做,否則回傳word的值 |
測驗檔案test內容如下:
#! /bin/bash
name="http://www.baidu.com"
echo -e '${name}:'"\t${name}"
echo -e '${#name}:'"\t${#name}"
echo -e '${name:7}:'"\t${name:7}"
echo -e '${name:11:5}:'"\t${name:11:5}"
string="abcdeabcdeabcdeabcd"
echo -e '${string}'"\t${string}"
echo -e '${string#a*e}'"\t${string#a*e}"
echo -e '${string##a*e}'"\t${string##a*e}"
echo -e '${string%c*d}'"\t${string%c*d}"
echo -e '${string%%c*d}'"\t${string%%c*d}"
echo -e '${string/abcde/ae}'"\t${string/abcde/ae}"
echo -e '${string//abcde/ae}'"\t${string//abcde/ae}"
運行:
./test
${name}: http://www.baidu.com
${#name}: 20
${name:7}: www.baidu.com
${name:11:5}: baidu
${string} abcdeabcdeabcdeabcd
${string#a*e} abcdeabcdeabcd
${string##a*e} abcd
${string%c*d} abcdeabcdeabcdeab
${string%%c*d} ab
${string/abcde/ae} aeabcdeabcdeabcd
${string//abcde/ae} aeaeaeabcd
計算變數長度的各種方式
name="http://www.baidu.com" # 統計變臉name值的長度
# 法一 wc命令
echo "${name}" |wc -L (-L表示統計所有行中的最大長度,也就可以用來統計單個變數的長度)
20
# 法二 利用數值計算expr命令
expr length "${name}"
20
# 法三 awk命令
echo "${name}" |awk '{print length($0)}'
20
# 法四 最快的方法:${#name}
echo "${#name}"
20
資料計算的命令
shell的邏輯運算子與算符運算子和其他語言大致一樣,這里就不展開將了,簡要列一下shell特有的相關命令和運算子,
| 運算子或命令 | 含義 |
|---|---|
| $(()) | 用于整數運算的常用運算子,效率很高,在前面加上$符號可以取出計算結果 |
| let | 用于整數運算,類似于(()) |
| expr | 可用于整數運算,但還有很多其他的額外功能,上面已經介紹過 |
| bc | Linux下的一個計算器程式,適合整數及小數運算,并不是內置的使用前需要安裝, |
| $[] | 用于整數運算,類似于$[] |
| awk | awk既可以用于整數運算,也可以用于小數運算 |
| declare | 定義變數值和屬性,-i引數可以用于定義整型變數,做運算 |
$(())與$[]更為常用,
┌──(root?kali)-[/home/kali/桌面]
└─# echo $[123+456]
579
┌──(root?kali)-[/home/kali/桌面]
└─# echo $((123*456))
56088
條件判斷
基本語法
test condition[ condition ](’condition‘是判斷條件,前后留有空格,)
使用上面方式進行對式子條件判斷后,需要使用echo $?顯示上面判斷的結果,如果是0即為真,如果是1即為假(與其他編程語言的true為1,false為0不同),
┌──(root?kali)-[/home/kali/桌面]
└─# name=haha
┌──(root?kali)-[/home/kali/桌面]
└─# test $name = haha # 注意符號兩邊也要留有空格
┌──(root?kali)-[/home/kali/桌面]
└─# echo $?
0
┌──(root?kali)-[/home/kali/桌面]
└─# [ $name = Haha ]
┌──(root?kali)-[/home/kali/桌面]
└─# echo $?
1
常用判斷條件
- 用于兩個整數之間比較
| 符號 | 意義 |
|---|---|
-eq |
等于(equal) |
-ne |
不等于(not equal) |
-lt |
小于(less than) |
-le |
小于等于(less equal) |
-gt |
大于(greater than) |
-ge |
大于等于(greater equal) |
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# a=20
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# [ $a -lt 15 ]
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# echo $?
1
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# [ $a -ne 21 ]
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# echo $?
0
2.按照檔案權限進行判斷
| 符號 | 意義 |
|---|---|
-r |
有讀的權限(read) |
-w |
有寫的權限(write) |
-x |
有執行的權限(execute) |
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# touch test
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# [ -r test ]
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# echo $?
0
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# [ -w test ]
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# echo $?
0
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# [ -x test ]
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# echo $?
1
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# ls
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# touch test
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# [ -r test ]
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# echo $?
0
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# [ -w test ]
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# echo $?
0
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# [ -x test ]
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# echo $?
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# ls -lah
總用量 8.0K
drwxr-xr-x 2 root root 4.0K 9月 7 19:42 .
drwxr-xr-x 3 kali kali 4.0K 9月 7 12:26 ..
-rw-r--r-- 1 root root 0 9月 7 19:42 test
- 按照檔案型別進行判斷
| 符號 | 意義 |
|---|---|
-e |
檔案存在(existence) |
-f |
檔案存在并且是一個常規的檔案(file) |
-d |
檔案存在并且是一個目錄(directory) |
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# ls
test
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# [ -e test ] # 是否存在檔案test?
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# echo $?
0
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# [ -f test ] # test是否存在?是否是一個常規檔案?
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# echo $?
0
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# [ -d test ] # test是否存在?是否是一個常規目錄?
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# echo $?
1
- 多條件判斷(通過邏輯運算子:&&和||)
&&表示前一條命令執行成功時,才執行后一條命令,||表示上一條命令執行失敗后,才執行下一條命令,
像C語言java語言都有三元運算子? :
如果要在shell編程中實作這種三元運算子的效果,可以通過&&和||兩個邏輯運算子實作,
例如:
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# a=15
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# [ $a -lt 20 ] && echo "$a < 20" || echo "$a >= 20"
15 < 20
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# [ abc ] && echo "have something" || echo "nothing"
have something
流程控制
if
基本語法:
(1)單分支
if [條件判斷式];then
程式
fi
或者
if [條件判斷式]
then
程式
fi
(2) 多分支
if [條件判斷]
then
程式
elif [條件判斷式]
then
程式
fi
示例:
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# cat if.sh
#! /bin/sh
if [ $1 = world ];then
echo "hello,$1!"
fi
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# ./if.sh world
hello,world!
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# a=21
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# if [ $a -gt 18 ] && [ $a -lt 35 ] ; then echo "you have become an adult";fi
you have become an adult
如果要將邏輯運算子也寫入中括號[]中,不能用&&和||,而應分別用-a(and) 和-o(or),如:
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# if [ $a -gt 18 -a $a -lt 35 ] ; then echo "you have become an adult";fi
you have become an adult
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# cat grade.sh
#! /bin/sh
if [ $1 -lt 60 ];then
echo "不及格";
elif [ $1 -ge 60 -a $1 -lt 80 ];then
echo "良"
else
echo "優"
fi
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# ./grade.sh 81
優
case
相比于其他語言的case語法,shell的case用法簡直逆天,
基本語法:
case $變數名 in
"值1")
如果變數的值等于值1,執行程式1
;;
"值2")
如果變數的值等于值2,執行程式2
;;
……
*)
如果變數的值都不是以上的值,則執行此程式
;;
esac # 這里和上面if的用法一樣,將case反過來寫成esac就成了結束詞,
示例:
1. case行尾必須為單詞”in“,每一個模式匹配必須以右括號”)“結束,
1. 雙分號“;;”表示命令序列結束,相當于java中的break,
1. 最后的“*)”表示默認模式,相當于java中的default
如:
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# cat grade2.sh
#! /bin/sh
case $1 in
1)
echo "this is one"
;;
2)
echo "this is two"
;;
3)
echo "this is three"
;;
*)
echo "no other choice"
;;
esac
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# ./grade2.sh 2
this is two
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# ./grade2.sh 4
no other choice
感覺這個版本的case語法是最奇怪的,
for
基本語法1:
for ((初始值;回圈控制條件;變數變化))
do
程式
done
這種雙小括號方式的for回圈語法,有些shell不支持,比如bash是支持這種for回圈語法的,而dash就不支持,
示例:
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# cat sum.sh
#! /bin/bash
for ((i=1; i<=$1; i++))
do
sum=$[ $sum + $i ]
done
echo $sum
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# ./sum.sh 100
5050
基本語法2:
for 變數 in 值1 值2 值3 ……
do
程式
done
還是推薦用這種語法的for回圈
示例:
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# cat for2.sh
#! /bin/sh
for i in apple banana grape
do
echo "I love $i"
done
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# ./for2.sh
I love apple
I love banana
I love grape
在shell中,花括號{}有特殊的用法,可以用來表示一個序列
如:{1..100}表示 “1到100的序列:1 2 3 4 5 6……”
┌──(kali?kali)-[~/桌面/scripts]
└─$ cat for2.sh
#! /bin/bash
for i in {1..100}
do
sum=$[$sum+$i]
done
echo sum=$sum
┌──(kali?kali)-[~/桌面/scripts]
└─$ ./for2.sh 100
sum=5050
學完for回圈以后就可以更好的看清楚之前說過的$*和$@的區別
詳細可以看我上一篇寫的關于shell的文章:https://www.cnblogs.com/jackie-lee/p/16643515.html中的內容,
while
基本語法:
while [條件判斷]
do
程式片段
done
示例:
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# cat while.sh
#! /bin/bash
i=0
while [ $i -le $1 ]
do
sum=$[ $sum + $i ]
i=$[$i+1]
done
echo $sum
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# ./while.sh 100
5050
以上回圈體中的計算式子寫法看上去十分反人類,其實,shell并不是為了能讓我們可以方便實作復雜編程而設計的一門高級語言,它本身是為了我們能夠通過一些簡單的命令來控制linux底層的內核,做一些底層操作,所以,語法相對其他語言更加底層,
現在很多shell支持另外的寫法,可以按照下面的方式寫,使用let命令,看上去相對簡單點:
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# cat while2.sh
#! /bin/bash
i=0
while [ $i -le $1 ]
do
let sum+=i
let i++
done
echo $sum
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# ./while2.sh 100
5050
當然只是一部分shell支持這個簡潔的寫法,建議兩個都要掌握,
read 命令詳解
基本語法:
? read (選項) (引數)
? 1)選項:
? -p:指定讀取值時的提示符;
? -t:指定讀取值時等待的時間(秒),如果-t不加表示一直等待
? 2)引數
? 變數:指定讀取值的變數名
?
示例:
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# cat read.sh
#! /bin/bash
read -t 7 -p "Enter your name in seconds:" name
echo welcome $name
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# ./read.sh
Enter your name in seconds:jackie
welcome jackie
說明:
read -t 7 -p "Enter your name in seconds:" name
指定時間7秒,7秒后停止read;
指定了給用戶看的提示符;
name是接收讀取用戶輸入值的變數名
函式
系統函式
basename
基本語法:
? basename [string/pathname][suffix](功能描述:basename命令會刪掉所有的前綴,包括最后一個('/')字符,然后將字串顯示出來,
? basename 可以理解為取路徑里的檔案名稱,和python中的os.path.basename(path)的函式功能一樣
? 選項:
? suffix為后綴,如果suffix被指定了,basename會將pathname或string中的suffix去掉
示例:
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# basename /home/kali/桌面/scripts/read.sh
read.sh
dirname
基本語法:
dirname 檔案絕對路徑 (功能描述:從給定的包含絕對路徑的檔案名中去除檔案名(非目錄的部分),然后退回剩下的路徑(目錄的部分))
dirname可以理解為取檔案路徑的絕對路徑名稱,和python中的os.path.dirname(path)的函式功能一樣
示例:
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# dirname /home/kali/桌面/scripts/read.sh
/home/kali/桌面/scripts
在腳本中列印出當前檔案名和檔案絕對路徑:
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# cat path.sh
#! /bin/bash
echo script name: $(basename $0 .sh)
echo script path: $(cd $(dirname $0);pwd) # 由于$0的值由腳本呼叫時采用的路徑來決定的,所以可能是相對或絕對路徑,需要先借助dirname $0切換到腳本所在目錄,然后利用 pwd獲得腳本的絕對路徑,
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# ./path.sh
script name: path
script path: /home/kali/桌面/scripts
┌──(root?kali)-[/home/kali/桌面]
└─# ./scripts/path.sh
script name: path
script path: /home/kali/桌面
date
顯示當前時間
后面加上引數后: date +%s表示當前的時間戳
示例:
根據當前時間生成日志檔案名:
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# cat log.sh
#! /bin/bash
filename="$1"_log_$(date +%s)
echo $filename
┌──(root?kali)-[/home/kali/桌面/scripts]
└─# ./log.sh jackie
jackie_log_1662725990
自定義函式
基本語法:
[function] 函式名[()]
{
Action
[return int;]
}
1)必須在呼叫函式地方之前,先宣告函式,shell腳本是逐行運行,不會像其他語言一樣先編譯
2)函式回傳值,可以通過
return回傳,通過$?獲取該值,如果不加return,將以函式體最后一條命令運行結果作為回傳值,return回傳的數值大小在(0-255)3)其中的
function和小括號()是可選的,參入的引數值默認為$n形式,4)呼叫函式時,和腳本傳入引數形式一樣:
函式名 引數1 引數2 ……
示例:
計算兩個輸入引數的和:
┌──(root?kali)-[/home/kali/桌面]
└─# cat add.sh
#! /bin/bash
function add(){
sum=$[$1 + $2]
return $sum
}
read -p "請輸入第一個整數:" a
read -p "請輸入第二個整數:" b
add $a $b
echo "a+b:"$?
呼叫add.sh腳本:
┌──(root?kali)-[/home/kali/桌面]
└─# ./add.sh
請輸入第一個整數:100
請輸入第二個整數:120
a+b:220
輸出正常,
但是如果回傳的結果sum值大于255呢?
┌──(root?kali)-[/home/kali/桌面]
└─# ./add.sh
請輸入第一個整數:200
請輸入第二個整數:100
a+b:44
顯然超過了255,回傳的值會是溢位255的部分,
如果希望函式能夠回傳超過255的值呢?可以按照如下操作:
┌──(root?kali)-[/home/kali/桌面]
└─# cat add2.sh
#! /bin/bash
function add(){
let sum=$1+$2
echo $sum
}
read -p "請輸入第一個整數:" a
read -p "請輸入第二個整數:" b
sum=$(add $a $b)
echo "兩個整數相加的值為:"$sum
函式體中的最后一個命令通過echo將要回傳的值回顯出來,然后函式體外通過$()呼叫函式add來接識訓顯出來的值即可,
┌──(root?kali)-[/home/kali/桌面]
└─# ./add2.sh
請輸入第一個整數:100
請輸入第二個整數:200
兩個整數相加的值為:300
不得不說看到這里感覺shell語法和其他編程語言大相徑庭,尤其是在函式這一塊,學這門語言還是要耐心,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/506028.html
標籤:其他
