Linux-shell編程入門基礎

文章目錄

  • 前言
  • Shell編程
    • bash特性
    • shell作用域
    • 變量
      • 環境變量
      • $特殊變量
      • $特殊狀態變量
    • $特殊符號(很重要)
    • 其他內置shell命令
    • shell語法的子串截取
      • 統計
    • 指令執行時間
    • 練習
    • shell特殊擴展變量
    • 父子shell的理解
    • 內置和外置命令
      • 區別
    • 數值計算
      • 雙括號(())運算
      • let
      • expr
        • expr模式匹配
      • bc
      • awk
      • 中括號
    • shell的條件判斷
      • test判斷
      • 中括號[]判斷
        • 中括號寫判斷符號
      • 雙中括號[[]]
    • if分支
    • case
    • for
    • while
    • 普通數組
    • 函數
      • 函數定義
      • 函數執行
      • 函數傳參
      • 如何分文件
      • 規范

前言

本篇文章就是一個過渡學習的,先入門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 "$*"
doecho "$var"
done
echo '=====$@===line========='
for var in $@
doecho "$var"
done
echo '==="$@"=====line========='
for var in "$@"
doecho "$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;donereal	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;donereal	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;donereal	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,否則返回ARG2ARG1 & ARG2       若兩邊的值都不為0 或為空,則返回ARG1,否則返回 0ARG1 < ARG2       ARG1 小于ARG2ARG1 <= ARG2      ARG1 小于或等于ARG2ARG1 = ARG2       ARG1 等于ARG2ARG1 != ARG2      ARG1 不等于ARG2ARG1 >= ARG2      ARG1 大于或等于ARG2ARG1 > ARG2       ARG1 大于ARG2ARG1 + ARG2       計算 ARG1 與ARG2 相加之和ARG1 - ARG2       計算 ARG1 與ARG2 相減之差ARG1 * ARG2       計算 ARG1 與ARG2 相乘之積ARG1 / ARG2       計算 ARG1 與ARG2 相除之商ARG1 % ARG2       計算 ARG1 與ARG2 相除之余數字符串 : 表達式		定位字符串中匹配表達式的模式match 字符串 表達式		等于"字符串 :表達式"substr 字符串 偏移量 長度	替換字符串的子串,偏移的數值從 1 起計index 字符串 字符		在字符串中發現字符的地方建立下標,或者標0length 字符串			字符串的長度

在使用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

需要注意的是,不要直接就是 [ n u m = 3 ] 這樣,因為你這樣就相當于執行了一個 [num=3]這樣,因為你這樣就相當于執行了一個 [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 <條件表達式>thencodeing...
fi#簡化
if <條件表達式>;thencodeing
fi

嵌套if

if <條件表達式>thencodeing...if <條件表達式>thenfi
fi

if-else

if <條件表達式>thencoding...
elsecoding...
fi

if-elif

if <條件表達式>thencoding
elif <條件表達式>thencoding
elsecoding...
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 循環列表(一定是列表哈)
doshell代碼
done

注意

循環列表可以是:
{1..100} shell命令自帶的生成1-100的序列,當然其他命令都可以比如seq
"1 2 3 4" 這種也能夠當成循環列表,以空格為分隔符號,會依次取出1 2 3 4文本文件中你cat出來每一行也能當作列表循環
for i in $(cat /etc/passwd) #這種讀取文件出來就是每一行作為一個變量
$()等于``,執行命令,不要忘記了,在這里回顧一下。

while

語法

while <條件表達式>
doshell代碼
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 $3return 返回值
}#函數有參數的調用方式如下(和腳本傳參一樣格式)
函數名 參數1 參數2 參數3

示例腳本:

[root@localhost cxk]# cat args_sh.sh 
function f(){echo $1 $2 $3echo "函數執行完畢。"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
fun1fun2exit 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函數來規范化我們的代碼執行邏輯,一方面是方便閱讀,二來也是對腳本的封裝模塊化能夠有更深的理解。

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

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

相關文章

MySQL InnoDB事務隔離的幾種級別

MySQL InnoDB是一種支持事務的存儲引擎&#xff0c;提供了多種事務隔離級別&#xff0c;分別是&#xff1a;讀未提交&#xff08;READ UNCOMMITTED&#xff09;&#xff0c;讀已提交&#xff08;READ COMMITTED&#xff09;&#xff0c;可重復讀&#xff08;REPEATABLE READ&am…

數據結構(Java):Stack相關OJ習題

1、括號匹配問題 . - 力扣&#xff08;LeetCode&#xff09; 1.1 思路分析 根據棧的先進后出原則&#xff0c;我們可以這樣解決問題&#xff1a; 遍歷字符串&#xff0c;遇見左括號就將左括號push入棧&#xff1b;遇見右括號就pop出棧&#xff0c;將出棧的元素和該右括號比較…

最簡單的vue3組件之間傳值

localStorage 是 HTML5 引入的一個 Web Storage API 的一部分&#xff0c;它允許網頁在用戶的瀏覽器上存儲數據。localStorage 提供了一種持久化的本地存儲方案&#xff0c;數據不會因為瀏覽器關閉而丟失&#xff0c;除非用戶或腳本顯式地刪除它們。 localStorage 是一種非常實…

批量提取網頁表格內容至excel文件

問題背景 將網頁的表格內容&#xff08;5237個股票信息&#xff09;復制粘貼到excel文件中 網址&#xff1a;A股上市公司名單-A股上市公司名錄-A股上市公司大全-商業計劃書-可研報告-中商產業研究院數據庫-中商情報網 實現代碼 # 導入包 import pandas as pd import time# 創…

Android中為什么不直接activity調用到view,使用viewrootimpl去與底層溝通,而要追加一個phonewindow來管理呢?

在Android的架構設計中&#xff0c;Activity、PhoneWindow 和 ViewRootImpl 各自扮演著不同的角色&#xff0c;它們之間的協作是為了實現一個更加靈活、可擴展和易于管理的UI系統。不直接從Activity調用到View&#xff0c;而是引入PhoneWindow來管理&#xff0c;主要有以下幾個…

超越傳統:3D生物打印如何利用擴散創造奇跡?

超越傳統&#xff1a;3D生物打印如何利用擴散創造奇跡&#xff1f; 組織工程和再生醫學領域迫切需要能夠模擬人體組織結構和功能的體外模型和組織替代物。然而&#xff0c;傳統的體外模型和組織替代物往往難以滿足高度特異性、復雜性和功能性的要求。3D生物打印技術應運而生&a…

Base64文件流查看下載PDF方法-CSDN

問題描述 數票通等接口返回的PDF類型發票是以Base64文件流的方式返回的&#xff0c;無法直接查看預覽PDF發票&#xff0c; 處理方法 使用第三方在線工具&#xff1a;https://www.jyshare.com/front-end/61/ 在Html代碼框中粘貼如下代碼 <embed type"application/pd…

技術開發分享:商品詳情APP原數據實時接口代碼解析

商品詳情app端原數據實時接口代碼解析主要包括以下幾個步驟&#xff1a; 獲取商品ID&#xff1a;首先需要從淘寶的分享鏈接中提取商品ID&#xff0c;可以通過正則表達式匹配的方式獲取。 構建請求URL&#xff1a;根據商品ID構建請求URL&#xff0c;通常包括淘寶的商品詳情API地…

未來互聯網的新篇章:深度解析Web3技術

隨著技術的不斷演進&#xff0c;Web3正逐漸成為引領未來互聯網發展的關鍵驅動力。本文將深入探討Web3技術的核心概念、關鍵特征以及其對未來互聯網生態的深遠影響&#xff0c;旨在幫助讀者全面理解和把握這一新興技術的發展方向和潛力。 1. Web3的基本概念和演進 Web3并非簡單…

為什么鍵盤上F和J這兩個鍵有兩個凸起的橫線呢?

不知道小伙伴們有沒有注意過&#xff0c;我們常用的電腦鍵盤上&#xff0c;為什么F和J這兩個鍵總是有兩個凸起的橫線的呢&#xff1f; 首先&#xff0c;讓我們來回顧一下這位陪伴我們多年的老朋友——鍵盤。從最初的打字機到現在的機械鍵盤、薄膜鍵盤&#xff0c;鍵盤的形態和…

新書速覽|Vue.js 3.x+Express全棧開發:從0到1打造商城項目

《Vue.js 3.xExpress全棧開發&#xff1a;從0到1打造商城項目》 1 本書內容 《Vue.js 3.xExpress全棧開發 : 從0到1打造商城項目》是一本詳盡的全棧開發教程&#xff0c;旨在通過Vue.js和Express框架引導讀者從零開始構建一個完整的電商項目。內容覆蓋電商項目的基本結構&…

C++——map和set類用法指南

一、前言 1.1 關聯式容器 關聯式容器也是用來存儲數據的&#xff0c;與序列式容器不同的是&#xff0c;其里面存儲的是<key,value>結構的鍵值對&#xff0c;在數據檢索時比序列式容器效率更高。 1.2 鍵值對 用來表示具有一一對應關系的一種結構&#xff0c;該結構中一般…

編程入門題:畫矩形(C語言版)

1.題目描述&#xff1a; 根據輸入的四個參數:a,b,c,f參數&#xff0c;畫出對應的矩形。前兩個參數 a,b為整數&#xff0c;依次代表矩形的高和寬:第三個參數c是一個字符&#xff0c;表示用來填充的矩形符號第四個參數 f為整數&#xff0c;0 代表空心&#xff0c;否則代表實心。具…

Redis如何高效實現定時任務

寫在文章開頭 redis通過單線程結合非阻塞事件輪詢機制實現高效的網絡IO和時間事件處理&#xff0c;這篇文章我們將從源碼的角度深入分析一下redis時間事件的設計與實現。 Hi&#xff0c;我是 sharkChili &#xff0c;是個不斷在硬核技術上作死的 java coder &#xff0c;是 CS…

項目三層架構詳情

三層架構 三層架構就是為了符合“高內聚&#xff0c;低耦合”思想&#xff0c;把各個功能模塊劃分為表示層&#xff08;UI&#xff09;、業務邏輯層&#xff08;BLL&#xff09;和數據訪問層&#xff08;DAL&#xff09;三層架構&#xff0c;各層之間采用接口相互訪問&#xf…

(正向)代理 vs. 反向代理

&#xff08;正向&#xff09;代理 vs. 反向代理 代理和反向代理都是針對用戶而言的。 一、&#xff08;正向&#xff09;代理——代理客戶端 1. 流程 代理會隱藏客戶端的真實信息&#xff08;IP、端口&#xff09;&#xff0c;代替客戶端在互聯網上發起請求&#xff0c;并將…

09:C語言進階篇一

C語言進階篇一 數據類型1.1、內存占用與sizeof運算符1.2、有符號數和無符號數1.3、整形數和浮點型數存儲方式1.4、數據類型轉換1.4.1、隱式轉換1.4.2、強制轉換 數據類型 基本數據類型&#xff1a;char&#xff0c;short&#xff0c;int&#xff0c;long&#xff0c;float&…

什么是RLHF(基于人類反饋的強化學習)?

什么是RLHF&#xff08;基于人類反饋的強化學習&#xff09;&#xff1f; 基于人類反饋的強化學習&#xff08;Reinforcement Learning from Human Feedback, RLHF&#xff09;是一種結合強化學習和人類反饋的技術&#xff0c;用于訓練智能體&#xff0c;使其行為更符合人類期…

哪些類型的工作需要六西格瑪綠帶培訓?

一、六西格瑪綠帶是什么&#xff1f; 首先&#xff0c;讓我們來了解一下六西格瑪綠帶。六西格瑪綠帶是六西格瑪管理體系中的一個重要角色&#xff0c;他們通常負責在項目中執行六西格瑪方法和工具&#xff0c;協助黑帶完成復雜的項目任務。綠帶需要掌握基本的六西格瑪知識和技…

OpenJudge | 最高的分數

目錄 描述輸入輸出樣例輸入樣例輸出思路方法一方法二 CodeCC 總時間限制: 1000ms 內存限制: 65536kB 描述 孫老師講授的《計算概論》這門課期中考試剛剛結束&#xff0c;他想知道考試中取得的最高分數。因為人數比較多&#xff0c;他覺得這件事情交給計算機來做比較方便。你能…