Linux-shell編程入門基礎

来源:https://www.cnblogs.com/dhan/p/18294949
-Advertisement-
Play Games

本篇文章就是一個過渡學習的,先入門shell腳本,由於作者有編程基礎,所以有些解釋的比較少。由於現在還在努力學習中,以後等本散修進階了之後再寫進階的、與網路安全更加貼合的shell編程 ...


目錄

前言

本篇文章就是一個過渡學習的,先入門shell腳本,由於作者有編程基礎,所以有些解釋的比較少。由於現在還在努力學習中,以後等本散修進階了之後再寫進階的、與網路安全更加貼合的shell編程

Shell編程

指定shebang的意思是指定腳本執行的解釋器

#!/bin/bash #指定bash執行,那這就是shell語言腳本了

#!/bin/python #指定python解釋器,那麼這個就是python語言腳本

#!/bin/perl #指定perl解釋器,那這個腳本就是perl語言腳本

bash特性

查看歷史指令最大存儲條數

echo $HISTSIZE

存放用戶執行的歷史指令的文件

echo $HISTFILE

快速查看歷史指令

!1000 #查看第1000條歷史指令是什麼
!! #執行上一條指令

反引號執行指令

`ls` #反引號中的字元會當成指令執行

文件是否能執行得看文件是否具有x執行許可權

ll filename #查看文件屬性
chmod +x filename #添加執行許可權 這樣直接+x就是a+x
有執行許可權的文件通常是標誌綠色的

執行shell腳本方式

source shell.sh
. shell.sh

./shell.sh
bash shell.sh
sh shell.sh

source和.是在當前環境中載入變數,所以你使用這兩個命令載入shell腳本後,裡面的變數就會載入到你當前的bash中,而不會開啟子shell,所以慎用這兩個命令。(這兩個source和.符號,在後面函數分文件中也會用到)

shell作用域

每個用戶家目錄下都有一個自己的變數文件,是在系統載入的時候載入

.bash_profile
該文件作用是先載入.bashrc
然後再載入你下麵定義的變數等等

image
這裡提前說明一下如何載入,註意是載入不是執行

source filename
. filename 

以上兩個都是載入文件的操作,這兩個方法都是可以在該文件沒有x執行許可權的時候進行載入
因為如果要按照shell腳本進行載入的話,那麼你裡面的變數都會變成局部變數,那麼腳本執行雖然也載入了,
但是執行完成後就會被釋放,出來後依然還是沒有成功載入你的變數

linux中執行shell腳本方式

./shell.sh
bash shell.sh
sh shell.sh

bash和sh單獨使用的話,就是進入一個子shell中,我們可以通過pstree查看。

可以通過exit退出子shell

安裝一個psmisc,主要用pstree功能來理解作用域,沒有也無所謂

yum install psmisc -y 
  • 下麵是通過bash開第一個子shell,通過pstree可以看到確實是進入了一個子shell中
    image
  • 下麵是通過sh進入的一個子shell,通過pstree可以看到確實是進入了一個子shell中
    image

查看一下兩個shell,pstree可以看到是不同bash的。
image
我們隨便定義一個變數,可以看到不同shell之間的變數是互通不了的,原因作用域的問題

作用域大概如下,age一般定義在自己bash中的變數是不能互通的:

每一個盒子都是一個shell盒子,他們之間的變數都是不能互通的
不管是他們的全局變數還是局部變數都是不可以互通
但是除非你定義在了系統變數,比如/etc/profile這種文件中,
這種文件是在系統載入的時候載入的文件,所以每一個用戶都會生效。
但是除非你自己盒子裡面有和你在系統文件中定義的變數,就會被覆蓋掉,以你自身的.bash_profile文件為準
image
總結:

shell的作用域說白了就是每一個shell登錄進來都是不一樣作用域,你要全局生效就去修改/etc/profile下的系統載入文件,但是你修改了不會立刻生效,你可以使用source /etc/profile 和 . /etc/profile就能夠載入一下該腳本文件,你的變數就會在你當前shell腳本生效,但是其他已經登錄進來的用戶不會生效,因為他沒有載入系統文件,除非他退出重新登錄或者source /etc/profile 或者 ./etc/profile才能載入生效。

變數


Linux 系統中環境變數約定好都是大寫,不容易和我們自己定義的出現衝突,也就是說我們定義的變數最好是小寫的


環境變數

查看變數相關指令

set #輸出所有變數,包括全局變數和局部變數
env 只顯示全局變數
declare 同set
export 顯示還有設置環境變數值,在linux命令中直接使用的話是臨時設置的哈

常見的環境變數

PATH:shell會到該變數定義的目錄中找命令和程式
PS1:基本提示符,對於 root 用戶是 #,對於普通用戶是 $
HISTSIZE:最大存儲的歷史記錄數
SHELL:該用戶使用的Shell,通常是/bin/bash
HOME:當前用戶給的預設主目錄
LANG:語言相關的環境變數,多語言可以修改此環境變數
USER:用戶名
LOGNAME:用戶的登錄名
HOSTNAME:主機的名稱
MAIL:當前用戶的郵件存放目錄

撤銷環境變數名

  • unset 變數名,刪除變數或者函數

設置只讀變數

  • readonly ,只有shell結束才能失效的變數

    readonly name='abc'
    name=123 #企圖修改的時候就會報錯下麵的信息
    -bash: name: 只讀變數
    

set 查看系統中所有的系統變數

通過下圖可以看到,我們每一個shell就算定義在了profile文件中,我們也要進行載入才能看到,就算我們直接grep該文件也是查看不到另一個shell中添加到profile中的變數,一定一定要使用source或者.符號進行載入才可以載入。
image
可以看到我們載入後就能夠看到和使用另一個shell添加進去的name變數了。
image
通過上面案例後,我們可以理解成:

set 就是查看系統中定義的全局變數還有局部變數,不用管他是查看哪個文件。
(PS:env就是只能看全局,比如我們用戶自己在shell命令終端中定義的變數只有set能看,env看不到。)

其他查看的類型不用瞭解太深,其實shell腳本用到的大多都是自己定的變數,更多變數以後就會慢慢接觸到。(說人話:我懶得查了)

$特殊變數

$0  獲取shell腳本的文件名以及腳本路徑

$n  獲取shell腳本執行的時候傳入的參數,比如$1就是獲取傳進來的第一個參數

$#  獲取執行的shell腳本後面的參數總個數,這個是統計參數個數的變數

$*  獲取shell腳本傳進來的所有參數,直接使用等於"$1" "$2" "$3"
"$*" 這樣加上引號是獲取所有參數,但是不是列表形式,而是整體"$1 $2 $3"

$@ 和 "$@" 都等於 $* ,他都是列表形式讓你迴圈

如下腳本輸出,看完就能理解這幾個的區別了。

#!/bin/bash
echo '=====$@===line========='
for var in "$*"
do
	echo "$var"
done
echo '=====$@===line========='
for var in $@
do
	echo "$var"
done
echo '==="$@"=====line========='
for var in "$@"
do
	echo "$var"
done

image

$特殊狀態變數

$? 上一次命令執行狀態返回值,0表示正確,非零表示失敗 #這裡終於明白了為什麼一開始學c語言的時候return 0是正常退出了!!!淚目!!
$$ 當前shell腳本的進程號
$! 上一次後臺進程的PID
$_ 上次執行的命令的最後一個參數

更詳細更多的特殊狀態變數解釋可以直接查看man手冊

man bash

$特殊符號(很重要)

${變數名}    #取出變數的值
$變數名      #取出變數值
$(命令)      #括弧中執行命令,然後返回結果
``          #反引號中執行命令,然後返回結果
()          #開啟子shell執行命令

其他內置shell命令

內置的shell有很多,但其實在學習Linux的時候就已經有學過一些了。比如:alias也是內置的shell命令

echo
printf
eval
exec
read

echo

-n 不換行輸出
-e 解析字元串彙總的特殊符號,
	比如:
	\n 換行
	\r 回車
	\t 製表符(四個空格)
	\b 退格

printf

echo需要加上-e才能識別特殊符號,那printf就是可以直接解析特殊符號的。

printf "hello\nworld\n"

eval

執行多個命令
eval ls;cd /tmp;ls

其實在linux中只使用分號也能實現多個命令執行。
這裡eval可能是為了在shell腳本中好執行??我也不太懂,以後再深入瞭解。。。

exec

不創建子進程然後執行你給的命令,然後執行結束後就直接退出當前shell,說白了就是exec執行命令後就會自動exit你當前的shell

image

read

read [-參數] [變數1 變數2 ...]

註意:變數1 2 這些是輸入的數據,然後按照順序給到變數,變數名可以隨便起,後面要使用該變數的時候按照正常的$符號取變數值即可。

-p #顯示提示信息,後面加上你要提示的字元串
-r #不對輸入的字元進行轉義,讀到什麼字元串就輸出什麼字元串
-t #限制用戶輸入的時間,單位秒
-s #靜默模式,不會顯示你輸入的內容,就像你修改密碼的時候也不會顯示出來
  • -p參數解釋

    read -p '請輸入數據:' name age
    echo $name 
    echo $age
    腳本讀到read這行的時候就會要求用戶輸入數據,然後數據會按照順序給到變數name和age
    
  • -t參數解釋

    read -t 5 -p "請輸入你要修改的名字:" name
    echo $name
    腳本讀到read這行的時候就會要求用戶輸入數據,然後數據給到name變數
    

shell語法的子串截取

這裡使用name作為變數,下麵都使用name

${name}         			返回變數值
${#name}        			返回name的字元長度(這個獲取長度命令很快)
${name:start}   			返回name變數的start下標開始以及後面的字元
${name:start:length}		返回name變數的start下標開始然後截取length個字元

下麵介紹刪除字元的
str_or_pattern意思是可以是字元也可以是正則匹配模式,最短和最長就是因為有正則模糊匹配
${name#str_or_pattern}		從變數開頭開始刪除匹配最短str_or_pattern
${name##str_or_pattern}		從變數開頭開始刪除匹配最短的str_or_pattern

${name%str_or_pattern}		從變數結尾開始刪除匹配最短的str_or_pattern
${name%%str_or_pattern}		從變數結尾開始刪除匹配最長的str_or_pattern

下麵介紹替換字元的
下麵這種方式有點像我們sed還有vim裡面自帶的字元替換,所以說Linux語法都是大差不差的哈
${name/pattern/string}		用string替換第一個匹配的pattern
${name//pattern/string}		用string替換所有匹配的pattern
  • 註意

    #上面的刪除字元#和%這兩個,#開頭一定要匹配上,比如name=123abcABC456abcABC
    #那麼我們要刪除的話肯定是1開頭的,如果不是1開頭就無效,給你返回源字元了
    [root@localhost ~]# echo ${name#1*c}
    ABC456abcABC
    [root@localhost ~]# echo ${name##1*c}
    ABC
    [root@localhost ~]# echo ${name##2*c} #匹配不正確導致的輸出原變數值
    123abcABC456abcABC
    
    
    #那麼同理%也是,只不過是從結尾開始匹配,那麼我們給的str_or_pattern結尾要和變數最後一個字元一樣才行哈
    [root@localhost ~]# echo ${name%b*C}
    123abcABC456a
    [root@localhost ~]# echo ${name%%b*C}
    123a
    [root@localhost ~]# echo ${name%%C*a} #匹配不正確導致的輸出原變數值
    123abcABC456abcABC
    

統計

  • 最快統計字元方式就是自帶的

    echo ${#name}
    
  • wc

    -L 統計字元數最多那一行,輸出他的字元數量
    -l 統計文件行數
    -c 統計文件字元數
    
  • expr length "字元"

    直接輸出字元長度,這裡可以使用變數,當然你用變數的話記得使用雙引號
    
    expr length "${name}"
    

指令執行時間

計算方式:time 指令

比如我們這裡統計上面統計字元長度哪個指令是速度最快的

待檢測數據為:

time for i in {1..10000};do str=`seq -s "ok" 10`;echo ${#str} &> /dev/null;done

修改${#str}部分為其他統計字元指令即可檢測不同指令之間的效率

知識點:

&>是1&2>的縮寫
&1是為了標識1不是一個文件,而是一個標準輸出,所以 2>&1意思是將標準錯誤輸入到標準輸出1中
command &> /dev/null 等於 command > /dev/null 2>&1

  • ${#str} 這種方式最快

    [root@localhost ~]# time for i in {1..10000};do str=`seq -s "ok" 10`;echo ${#str} &> /dev/null;done
    
    real	0m10.319s
    user	0m4.307s
    sys	0m6.660s
    
  • wc -L 需要使用到管道符一般都比較慢

    [root@localhost ~]# time for i in {1..10000};do str=`seq -s "ok" 10`;echo $str | wc -L &> /dev/null;done
    
    real	0m19.679s
    user	0m12.981s
    sys	0m13.072s
    
  • expr length "${str}"

    [root@localhost ~]# time for i in {1..10000};do str=`seq -s "ok" 10`;expr length "${str}" &> /dev/null;done
    
    real	0m19.057s
    user	0m8.865s
    sys	0m11.688s
    

練習

數據

[root@localhost ~]# touch whoisdhan_{1..10}_nono
[root@localhost ~]# 
[root@localhost ~]# ls who*
whoisdhan_10_nono  whoisdhan_4_nono  whoisdhan_8_nono
whoisdhan_1_nono   whoisdhan_5_nono  whoisdhan_9_nono
whoisdhan_2_nono   whoisdhan_6_nono
whoisdhan_3_nono   whoisdhan_7_nono

將上面的文件所有帶_nono的,都替換為空,比如whoisdhan_10_nono 變成 whoisdhan_10

答案不止一個,下麵是我的答案

for var in `ls who*`;do mv $var ${var//_nono/};done

#從這裡可以擴展一下思維。我第一時間想到的是find命令進行查找,其實不用,因為我們的文件就在該目錄下了,直接ls通配符模糊匹配即可。

shell特殊擴展變數

註意:這裡我個人認為是適合用在開發腳本的時候,對腳本接受到的參數進行篩選甄別。

${parameter:-str} #如果parameter為空的時候,就返回str字元串,不為空那就返回parameter

${parameter:=str} #如果parameter為空的時候,將parameter賦值為str並且返回str值

${parameter:?str} #如果parameter為空的時候,將str當作錯誤內容輸出,否則輸出parameter值
就像下麵這樣
[root@localhost ~]# echo ${q:?空變數}
-bash: q: 空變數

${parameter:+str} #parameter為空的時候啥也不做,如果不為空那就返回str(可以用來判斷某些參數是否為空)
就像下麵這樣
[root@localhost ~]# echo ${name:+不為空}
不為空

父子shell的理解

下麵是我看超哥教程的一份圖解:
image

為什麼要理解父子shell的關係,原因是因為我們shell編程中一個括弧就能夠開啟一個子shell,目的是不讓某些操作比如Ping指令將我們當前的shell卡主,這樣的話你可以開一個子shell去執行ping這種指令,然後可以讓shell腳本繼續執行下去。

image
$BASH_SUBSHELL該變數是檢測開啟了幾個子shell

(cd ~;pwd;ls;(cd /tmp;ls;(echo "開啟了:$BASH_SUBSHELL 個子shell")))

image

內置和外置命令

識別內置還是外置

type cd
type rename

快速查看系統有哪些是內置命令

compgen -b

區別


先認識一下兩個的意思

  • 內置

    在系統啟動時就載入記憶體,常駐記憶體,執行效率更高,但是占用資源
    
  • 外置

    系統需要從硬碟中讀取程式文件,再讀入記憶體載入
    

二者區別:

內置就是不開啟子進程,直接在當前shell中執行,外置就是需要下載的一些系統命令,使用外置命令的時候需要開啟一個子進程執行。

數值計算

雙括弧(())運算

image

((i=i+1))  #雙括弧裡面進行一系列的運算
$((i=i+1)) #加個$符號就是取你計算出來的結果
((條件判斷)) #為真返回1,為假返回0

註意:

假設你有一個變數名為name=123
當你使用雙括弧進行name變數運算的時候是按照你name本來的值進行運算的,同時可以修改name的值。
((name++))

echo $name
124

計算器簡易版

#!/bin/bash
echo $(($1))

image

let

age=5
let age+=5 #let後面就能夠直接使用變數進行計算了
等同於
$((age+=5))  #但是這種是會報錯的,因為會把結果10當成命令執行,但是我們賦值是賦值成功了的

expr

複習一下,之前我們使用expr進行字元長度計算

直接輸出字元長度,這裡可以使用變數,當然你用變數的話記得使用雙引號
expr length "${name}"

expr --help

將表達式的值列印到標準輸出,分隔符下麵的空行可提升算式優先順序。
可用的表達式有:

  ARG1 | ARG2       若ARG1 的值不為0 或者為空,則返回ARG1,否則返回ARG2

  ARG1 & ARG2       若兩邊的值都不為0 或為空,則返回ARG1,否則返回 0

  ARG1 < ARG2       ARG1 小於ARG2
  ARG1 <= ARG2      ARG1 小於或等於ARG2
  ARG1 = ARG2       ARG1 等於ARG2
  ARG1 != ARG2      ARG1 不等於ARG2
  ARG1 >= ARG2      ARG1 大於或等於ARG2
  ARG1 > ARG2       ARG1 大於ARG2

  ARG1 + ARG2       計算 ARG1 與ARG2 相加之和
  ARG1 - ARG2       計算 ARG1 與ARG2 相減之差

  ARG1 * ARG2       計算 ARG1 與ARG2 相乘之積
  ARG1 / ARG2       計算 ARG1 與ARG2 相除之商
  ARG1 % ARG2       計算 ARG1 與ARG2 相除之餘數

  字元串 : 表達式		定位字元串中匹配表達式的模式

  match 字元串 表達式		等於"字元串 :表達式"
  substr 字元串 偏移量 長度	替換字元串的子串,偏移的數值從 1 起計
  index 字元串 字元		在字元串中發現字元的地方建立下標,或者標0
  length 字元串			字元串的長度

在使用expr進行計算的時候,符號與數據之間記得加上空格才能夠識別成功過,和變數賦值不一樣哈


加減乘除

expr 2 + 3
expr 2 - 3
expr 2 \* 3 #乘法這裡要對乘號進行字元轉義
expr 2 / 3

判斷符號

expr 1 \> 2
expr 1 \< 2

expr模式匹配

: 冒號,計算字元串的數量
.* 任意字元串重覆0或多次

看一個語法就理解了(就是有點奇怪,用冒號作為計算字元串標誌)

str=str.aaa.bbb
expr $str ":" "st.*b"
11

意思是計算出str.aaa.bbb字元一共11個字元數量
"st.*b"這個是正則匹配哈,特殊符號記得加轉移\

說白了expr就是正則模式匹配上了的,就統計你那個匹配上的字元,但是expr匹配模式是從字元串開始匹配的,所以只能規定後面的截止字元,

比如expr str.abc.abwwwc ":" "a*c"這樣是匹配不成功的,因為字元串是s開頭,而你給的匹配模式是a開頭。

bc

bc計算器

bc是可以直接當作電腦使用的。你直接敲bc命令進入後,直接輸入加減乘除這些式子回車都能夠給你輸出接過來。

[root@localhost ~]# bc
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'. 
1+1
2
(1+2)*3
9
9*9
81

通過管道符計算

echo "4*4" | bc
echo '1+1' | bc


[root@localhost ~]# echo '9*3' | bc
27
[root@localhost ~]# echo "1+2*3" | bc
7

練習:計算1..100的總和

方式一:echo {1..100} | tr ' ' '+' | bc

方式二:seq -s '+' 100 | bc

方式三:seq -s ' + ' 100 | xargs expr  
方式三我的理解:首先xargs不加-i參數是因為-i是要配合{}一起使用,然後是一個一個的傳進去,但是expr是expr 1 + 2這樣的,所以我們就不能用-i,那麼我們也不能直接 seq -s ' + ' 100 | expr直接管道符接,因為相當於字元串過去了,即相當於expr "1 + 2 + ..",那我們要配合xargs這種是接到"1 + 2 + .."後,當參數給到exrp而不是整個字元串給他,那麼就剛好等於expr 1 + 2 + 3 + .. 

awk

知道這種格式用法即可了

echo "2 3" | awk '{print($1*$2)}'  #等於2*3=6

中括弧

num=3

$[num+=2]

$[num-1]

[root@localhost ~]# num=3
[root@localhost ~]# res=$[num+=5]
[root@localhost ~]# echo $res
8

需要註意的是,不要直接就是$[num=3]這樣,因為你這樣就相當於執行了一個$[num=3]取出來的結果作為命令使用,當然num=3是執行成功了的哈。

shell的條件判斷

test判斷

-e 測試文件或目錄是否已存在,存在則返回真,否則返回假
-f 判斷文件是否是普通文件類型
-d 判斷是否是目錄類型
-n 判斷字元串不為空則為真,理解為 no zero
-z 判斷字元串為空時候為真,理解為 zero
-r 判斷當前用戶對該文件是否有許可權查看
-u 判斷該文件是否具有SUID屬性
-g 判斷該文件是否具有SGID屬性


比較參數
-eq 相等
-ne 不相等
-gt 大於
-lt 小於
-ge 大於等於
-le 小於等於


-a (and) 比如:test -r hello -a -w hello 
#判讀用戶對該hello文件是否有r讀取和w寫入許可權
-o (or)  比如:test -r hello -o -w hello
#判斷用戶對該hello文件是否有r讀取或者w寫入任意一個許可權

! (not) 表示非,例如:test ! -r hello
表示當用戶對該文件不具有r讀取許可權的時候就返回true,
註意寫的時候! -r之間一定要有空格,否則會報錯,不能連在一起寫,因為-r是參數,除非你是等於號就可以連在一起!=
  • -e

    簡單做一個練習:判斷hello文件是否存在,存在則列印“文件已存在” 否則列印 “文件成功創建” 並且創建hello文件

    test -e "hello" && echo "文件已存在" || (touch hello && echo "文件成功創建")
    
  • -f

    判斷這個文件是否是普通文件類型,如果是就列印yes否則列印no

    test -f hello && echo yes || echo no  
    
  • -d

    判斷是否是目錄類型

    test -d hello && echo yes || echo no
    
  • -n

    判斷字元是否為空,不為空則列印str_yes,否則列印str_no

    str=''
    test -n "$str" && echo str_yes || echo str_no
    
  • -r

    判斷用戶對文件是否有r讀取許可權

    test -r "hello" && echo yes || echo no
    
  • -w

    判斷用戶對文件是否有w寫許可權

  • -x

    判斷用戶對文件是否有x執行許可權

註意:如果你使用root來測試的話只能返回yes,因為root許可權是最大的。

中括弧[]判斷

註意:[]的兩邊一定要一定要加上空格,否則會出錯,這裡在if使用中括弧的時候是一樣的。

文件名和目錄名最好使用引號引起來,雖然可以不用引號,但是不敢擔保你的文件是否有空格隔開。

格式:[ 條件表達式 ]

參數

-f 測試普通文件是否存在
-d 測試目錄是否存在

-r
-w
-x
以上三個都是判斷用戶對文件是否有r讀取、-w寫入、-x執行許可權。


比較參數
-eq 相等
-ne 不相等
-gt 大於
-lt 小於
-ge 大於等於
-le 小於等於


-a (and) 比如:[ -f hello -o -f world ] && echo yes || echo no  
-o (or)  比如:[ -f hello -o -f world ] && echo yes || echo no

! (not) 表示非,例如:[ ! -f hello ] && echo yes || echo no
表示當用戶對該文件不具有r讀取許可權的時候就返回true,
註意寫的時候! -r之間一定要有空格,否則會報錯,不能連在一起寫,因為-r是參數,除非你是等於號就可以連在一起!=
  • 判斷hello文件是否存在,存在就輸出yes 否則就輸出 no

    [ -f hello ] && echo yes || echo no
    
  • 判斷hello目錄是否存在,存在就輸出yes 否則就輸出no

    [ -d hello ] && echo yes || echo no
    

中括弧寫判斷符號

註意:在中括弧中寫判斷符號的時候,數據與判斷符號和數據之間都要用空格隔開,包括中括弧也要空格哈,比如下麵

(後面會解釋為什麼使用轉移符號=)

[ "${name}" \= "123" ] && echo yes || echo no 

註意:這裡使用一個等號還是兩個等號都是一樣的哈。
意思是如果該變數name等於123的話就echo yes 否則 no

同理其他單個的符號也要空格,雙個不用
[ 1 \= 1 ]

image
使用數學比較符號的時候記得使用轉義符

[ 1 \> 2 ] 這樣才對,否則你使用[ 1 > 2 ]是錯誤的

下麵兩語句執行以下就知道結果了
[ 1 \> 2 ] && echo yes || echo no
[ 1 > 2 ] && echo yes || echo no

總結:使用數學運算符的話,如果是單個字元的就要使用轉移符號\,如果是!=或者==或者>=這種就不用加轉義符號。

雙中括弧[[]]

格式:[[ 條件表達式 ]]

使用起來和單中括弧的區別就是:雙中括弧不用寫轉義符,就可以直接識別> < = ,那麼雙中括弧同時還支持正則表達式匹配。

然後其他單中括弧支持的在雙中括弧里也能用。
但是我們平時用的比較多的是單中括弧。

總結括弧的知識:

image

if分支

註意:條件表達式可以是很多種,我們上面學的shell條件判斷方式否可以使用

單分支

if <條件表達式>
	then
	codeing...
fi

#簡化
if <條件表達式>;then
	codeing
fi

嵌套if

if <條件表達式>
	then
	codeing...
	if <條件表達式>
		then
	fi
fi

if-else

if <條件表達式>
	then
	coding...
else
	coding...
fi

if-elif

if <條件表達式>
	then
	coding
elif <條件表達式>
	then
	coding
else
	coding...
fi

case

註意:case的出現是可以讓你少用if else,同時他也是一個菜單化的這麼一個命令。

格式

語法

case $choice in 
1)
	shell代碼
	;;
2)
	shell代碼
	;;	
3)
	shell代碼
	;;
*) #這個是固定的,相當於我們編程中的default,就是上面的選項都沒有被$變數的值的時候就會跳到這裡來,在shell中一般是用來寫提示信息的。
	shell代碼
	;;
esac

#為什麼是esac,很簡單,我們學習if的時候是用fi解釋,就是if倒過來,那麼case的結束也是倒過來esac

註意:

1)
2)
3)
裡面的123可以隨便,只要你的$變數可以找到這個裡面,你可以隨便寫,可以是:
qqq)
reg)
adgsaf)
*)
隨便寫,只要你的$變數能夠找到即可。

*)最後一個是固定的

for

語法

for 變數名 in 迴圈列表(一定是列表哈)
do
	shell代碼
done

註意

迴圈列表可以是:
{1..100} shell命令自帶的生成1-100的序列,當然其他命令都可以比如seq
"1 2 3 4" 這種也能夠當成迴圈列表,以空格為分隔符號,會依次取出1 2 3 4

文本文件中你cat出來每一行也能當作列表迴圈
for i in $(cat /etc/passwd) #這種讀取文件出來就是每一行作為一個變數
$()等於``,執行命令,不要忘記了,在這裡回顧一下。

while

語法

while <條件表達式>
do
	shell代碼
done

註意

這個條件表達式和之前學的一樣,shell的條件判斷表達式能寫的while照樣可以拿來當條件表達式,不過一般都是用 [] 單中括弧的比較多

普通數組

定義

數組名=(值1 值2 值3)

取數組值

#根據下標取值
${數組名[下標]}  #不能用$數組名[下標] ,取不到數組值

#取數組中所有的值
${數組名[*]}
${數組名[@]}

#計算數組長度
${#數組名[@]}
${#數組名[*]}
#解釋:這裡很巧妙使用了我們上面說的#取字元長度的寫法,這裡就變成了取數組長度。比如$*和$@都是取所有參數,然後我們這裡就是取數組所有值,那麼再結合之前學的統計字元長度${#name}這種,就完美解釋和理解了為什麼計算數組長度是用${#數組名[@]}這個樣子了。

函數

說明:函數必須先定義再執行

註意:return 和 exit 是不同的,exit是結束shell環境,而return是結束函數執行。

函數定義

語法格式如下

#第一種
function 函數名(){
	函數體
	return 返回值
}

#第二種
function 函數名{
	函數體
	return 返回值
}

#第三種
函數名(){
	函數體
	return 返回值
}

函數執行

#執行方式
函數名

函數名(參數1 [,參數2,...] )

函數傳參

說明:在shell腳本中,傳參方式和你輸入的參數一樣,我們平常的比如touch ,touch 傳參數是 touch 文件名,那麼函數傳參也是這樣。同時,函數獲取參數方式和腳本獲取參數方式是一樣的。(這句話理解不了就看下麵的例子)

function 函數名(){
	echo $1 $2 $3
	return 返回值
}

#函數有參數的調用方式如下(和腳本傳參一樣格式)
函數名 參數1 參數2 參數3

示例腳本:

[root@localhost cxk]# cat args_sh.sh 
function f(){
	echo $1 $2 $3
	echo "函數執行完畢。"
	return 0
}

f "var1" "var2" "var3"

exit 0
[root@localhost cxk]# bash args_sh.sh 
var1 var2 var3
函數執行完畢。

如何分文件

如果你要分文件,那麼可以使用source 或者 .符號進行當前執行shell的bash中載入進來,所以這就是為什麼我們不同shell之間就算定義了系統變數,也要重新載入的原因了吧 。

fun.sh文件

. fun.sh
fun1

fun2

exit 0

main.sh文件

#!/bin/bash
fun1(){
	echo "fun11111 runing..."
}

fun2(){
	echo "fun22222 runing..."
}

執行main.sh文件(可以看到成功分文件執行成功)

[root@localhost cxk]# bash main.sh
fun11111 runing...
fun22222 runing...
[root@localhost cxk]# 

規範

學過編程的同學都知道,我們程式主入口的名字一般都是main,
雖然我們shell中沒有固定的main函數,但是我們還是進行一些規範化操作。

比如:
fun1(){}
fun2(){}
在定義了一系列函數之後,我們最後要寫一個main函數來規範化我們的代碼執行邏輯,一方面是方便閱讀,二來也是對腳本的封裝模塊化能夠有更深的理解。

本文來自博客園,作者:竹等寒,轉載請註明原文鏈接。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 痞子衡嵌入式半月刊: 第 104 期 這裡分享嵌入式領域有用有趣的項目/工具以及一些熱點新聞,農曆年分二十四節氣,希望在每個交節之日準時發佈一期。 本期刊是開源項目(GitHub: JayHeng/pzh-mcu-bi-weekly),歡迎提交 issue,投稿或推薦你知道的嵌入式那些事兒。 上期回 ...
  • 寫在前面 本隨筆是非常菜的菜雞寫的。如有問題請及時提出。 可以聯繫:[email protected] GitHhub:https://github.com/WindDevil (目前啥也沒有 官方文檔 仍然是一上來就丟出來的官方文檔. 只摘抄了我覺得有意思的部分: 實現特權級機制的根本原因是應用程 ...
  • 本章將和大家分享Linux常用的文件操作命令。廢話不多說,下麵我們直接進入主題。 一、目錄切換(cd命令) 在Linux系統中,cd 是一個用於切換當前工作目錄的命令,它是 "change directory" 的縮寫。基本用法如下所示: 1、不帶參數 示例:cd 或 cd~ 如果cd命令後沒有跟任 ...
  • 一、Certutil 介紹 Windows有一個名為CertUtil的內置程式,可用於在Windows中管理證書。使用此程式可以在Windows中安裝,備份,刪除,管理和執行與證書和證書存儲相關的各種功能。 CertUtil的一個特性是能夠從遠程URL下載證書或任何其他文件,因為certutil是w ...
  • 第十二章 跑馬燈實驗 1)實驗平臺:正點原子DNK210開發板 2)章節摘自【正點原子】DNK210使用指南 - CanMV版 V1.0 3)購買鏈接:https://detail.tmall.com/item.htm?&id=782801398750 4)全套實驗源碼+手冊+視頻下載地址:http ...
  • 第十一章 FPIOA管理器實驗 1)實驗平臺:正點原子DNK210開發板 2) 章節摘自【正點原子】DNK210使用指南 - CanMV版 V1.0 3)購買鏈接:https://detail.tmall.com/item.htm?&id=782801398750 4)全套實驗源碼+手冊+視頻下載地 ...
  • 1.檢查原始數據 原始數據展示如下: 工況 工況1 工況2 工況3 工況4 工況5 M 89.37 86.05 92.95 87.44 73.56 DF-1 87.45 80.98 89.68 84.43 73.46 DF-2 86.00 81.54 89.68 84.43 73.46 UP 85. ...
  • liwen01 2024.07.07 前言 yaffs 是專為nand flash 設計的一款文件系統,與jffs 類似,都是屬於日誌結構文件系統。與jffs 不同的是,yaffs 文件系統利用了nand flash 一些特有屬性,所以在數據讀寫擦除和回收上都有較大的差異。 關於jffs2文件系統的 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...