主頁 > 作業系統 > 一篇文章Shell腳本快速入門

一篇文章Shell腳本快速入門

2020-09-30 04:04:48 作業系統

Shell腳本基礎入門

Bash注釋

Bash只支持單行注釋,使用#開頭的都被當作注釋陳述句:

# 整行注釋
echo hello world # 行尾注釋

通過Bash的一些特性,可以取巧實作多行注釋:

: '
注釋1
注釋2
'

: <<'EOF'
注釋1
注釋2
EOF

____='
注釋1
注釋2
'

但是,別閑的蛋疼去用取巧的多行注釋,安心用#來注釋,

Bash基本資料型別

Bash中基本資料型別只有字串型別,連數值型別都沒有(declare -i可強制宣告數值型別),

比如:

# 都會當作字串
echo haha
echo 1234

Bash字串串聯

Bash中字串的串聯操作,直接將兩段資料連接在一起即可,不需要任何運算子,

例如:

echo "junma""jinlong"
echo 1234 5678

命令基本知識

變數賦值和參考變數

a=3
echo $a

a="www.junmajinlong.com"
echo $a

a='hello world'
echo $a

Shell中可以參考未定義的變數:

echo $xyzdefabc

可以定義空變數:

a=
echo $a

變數替換

變數替換是指在命令開始執行前,Shell會先將變數的值替換到參考變數的位置處,

例如:

a="hello"
echo $a world

在echo命令開始執行前,Shell會取得變數a的值hello,并將它替換到命令列的$a處,于是,在echo命令開始執行時,命令列已經變成:

echo hello world

除了變數替換,Shell還會做其它替換:

  • 命令替換
  • 行程替換
  • 算術運算替換
  • 大括號擴展
  • 波浪號擴展
  • 路徑擴展

這些擴展和替換,都是Shell在呼叫命令之前就完成的,這和其它語言決議代碼的方式不一樣,

學習Shell如何做命令列決議很重要,如果不掌握命令列決議,當遇到命令列語法錯誤后很可能會花掉大量無謂的時間去除錯命令,而掌握命令列決議后,就會對命令生命周期了如執掌,不敢說一次就能寫對所有命令列,但能節省大量除錯時間,對寫命令列和寫腳本的能力也會上升一個層次,

命令替換

使用反引號或$()可以執行命令替換,

`cmd`
$(cmd)

命令替換是指先執行cmd,將cmd的輸出結果替換到$()或反引號位置處,

例如:

echo `id root`
echo $(id root)

在echo命令執行前,會先執行id命令,id命令的執行結果:

$ id root
uid=0(root) gid=0(root) groups=0(root)

所以會將結果uid=0(root) gid=0(root) groups=0(root)替換$(id root),于是,echo命令開始執行時,命令列已經變成了:

echo uid=0(root) gid=0(root) groups=0(root)

算術運算

$[]$(())或let命令可以做算術運算,

let是單獨的命令,不能寫在其它命令列中,

a=3
let a=a+1
echo $a

$[]$(())可以寫在命令列內部,Shell在決議命令列的時候,會對它們做算術運算,然后將運算結果替換到命令列中,

a=33
echo $[a+3]
echo $((a+3))

因為變數替換先于算術替換,所以,使用變數名或參考變數的方式都可以:

a=333
echo $[$a+3]
echo $(($a+3))

退出狀態碼

每個命令執行后都會有對應的行程退出狀態碼,用來表示該行程是否是正常退出,

所以,在命令列中,在Shell腳本中,經常會使用特殊變數$?判斷最近一個前臺命令是否正常退出,

通常情況下,如果$?的值:

  • 為0,表示行程成功執行,即正常退出
  • 非0,表示行程未成功執行,即非正常退出
  • 但非0退出狀態碼并不一定表示錯誤,也可能是正常邏輯的退出

另外,在Shell腳本中,所有條件判斷(比如if陳述句、while陳述句)都以0退出狀態碼表示True,以非0退出狀態碼為False,

exit命令

exit命令可用于退出當前Shell行程,比如退出當前Shell終端、退出Shell腳本,等等,

exit [N]

exit可指定退出狀態碼N,如果省略N,則默認退出狀態碼為0,即表示正確退出,

后臺執行命令&

在命令的結尾使用&符號,可以將這個命令放入后臺執行,

命令放入后臺后,會立即回到Shell行程,Shell行程會立即執行下一條命令(如果有)或退出,

使用$!可以獲取最近一個后臺行程的PID,

sleep 20 &
echo $!

使用wait命令可以等待后臺行程(當前Shell行程的子行程)完成:

wait [n1 n2 n3 ...]

不給定任何引數時,會等待所有子行程(即所有后臺行程)完成,

sleep 5 &
wait
echo haha

多命令組合

Shell中有多種組合多個命令的方式,

1.cmd1退出后,執行cmd2

cmd1;cmd2

2.cmd1正確退出(退出狀態碼為0)后,執行cmd2

cmd1 && cmd2

3.cmd1不正確退出后,執行cmd2

cmd1 || cmd2

4.邏輯結合:&&||可以隨意結合

# cmd1正確退出后執行cmd2,cmd2正確退出后執行cmd3
cmd1 && cmd2 && cmd3...

# cmd1正確退出則執行cmd2,cmd1不正確退出會執行cmd3
# cmd1正確退出,但cmd2不正確退出,也會執行cmd3
cmd1 && cmd2 || cmd3

# cmd1正確退出會執行cmd3
# cmd1不正確退出會執行cmd2,cmd2正確退出會執行cmd3
cmd1 || cmd2 && cmd3

5.將多個命令分組:小括號或大括號可以組合多個命令

# 小括號組合的多個命令是在子Shell中執行
# 即會先創建一個新的Shell行程,在執行里面的命令
(cmd1;cmd2;cmd3)

# 大括號組合的多個命令是在當前Shell中執行
# 大括號語法特殊,要求:
#   1.開閉括號旁邊都有空白,否則語法決議錯誤(決議成大括號擴展)
#   2.寫在同一行時,每個cmd后都要加分號結尾
#   3.多個命令可分行書寫,不要求分號結尾
{ cmd1;cmd2;cmd3; }
{
  cmd1
  cmd2
  cmd3
}

基本重定向

軟體設計認為,程式應該有一個資料來源、資料出口和報告錯誤的地方,在Linux系統中,每個程式默認都會打開三個檔案描述符(file descriptor,fd):

  • fd=0:標準輸入,表示程式默認從哪里讀取資料
  • fd=1:標準輸出,表示程式默認將資料輸出到哪里
  • fd=2:標準錯誤,表示程式默認將錯誤資訊輸出到哪里

檔案描述符,說白了就是系統為了跟蹤打開的檔案而分配給它的一個數字,這個數字和檔案有對應關系:從檔案描述符讀取資料,即表示從對應的檔案中讀取資料,向檔案描述符寫資料,即表示向對應檔案中寫入資料,

Linux中萬物皆檔案,檔案描述符也是檔案,默認:

  • fd=0的標準輸入是/dev/stdin檔案
  • fd=1的標準輸出是/dev/stdout檔案
  • fd=2的標準錯誤是/dev/stderr檔案

這些檔案默認又是各個終端的軟鏈接檔案:

$ ls -l /dev/std*
lrwxrwxrwx 1 root root 15 Jan  8 20:26 /dev/stderr -> /proc/self/fd/2
lrwxrwxrwx 1 root root 15 Jan  8 20:26 /dev/stdin -> /proc/self/fd/0
lrwxrwxrwx 1 root root 15 Jan  8 20:26 /dev/stdout -> /proc/self/fd/1

$ ls -l /proc/self/fd/
lrwx------ 1 root root 64 Jan 16 10:40 0 -> /dev/pts/0
lrwx------ 1 root root 64 Jan 16 10:40 1 -> /dev/pts/0
lrwx------ 1 root root 64 Jan 16 10:40 2 -> /dev/pts/0
lr-x------ 1 root root 64 Jan 16 10:40 3 -> /proc/75220/fd

所以,默認情況下讀寫資料都是終端,例如:

# 資料輸出到終端
$ echo haha
$ cat /etc/fstab

# 從終端讀取資料
$ cat
hello   # 在終端輸入
hello   # 在終端輸出
world   # 在終端輸入
world   # 在終端輸出
^C

改變檔案描述符對應的目標,可以改變資料的流向,比如標準輸入fd=1默認流向是終端設備,若將其改為/tmp/a.log,便能讓資料寫入/tmp/a.log檔案中而不再是終端設備中,

在Shell中,這種改變檔案描述符目標的行為稱為重定向,即重新確定資料的流向,

其實,檔案描述符有很多類操作,包括fd的重定向、fd的分配(open,即打開檔案)、fd復制(duplicate)、fd的移動(move)、fd的關閉(close),現在只介紹基礎重定向操作,

Shell中,基礎重定向操作有以下幾種方式:

  • [n]>file:覆寫式輸出重定向,輸出到fd=n的資料改變流向輸出到file檔案中,file不存在則創建,file存在則先清空再寫入資料
    • 省略n時>file,等價于1>file,即標準輸出覆寫重定向到file檔案中
  • [n]>>file:追加式輸出重定向,輸出到fd=n的資料改變流向輸出到file檔案的尾部,file不存在則創建,file存在則直接追加在檔案尾部
    • 省略n時>>file,等價于1>>file,即標準輸出追加重定向到file檔案中
  • [n]<file:輸入重定向,以讀取模式打開file檔案并分配fd=n,file不存在則報錯
    • 省略n時<file,等價于0<file,即直接從file中讀資料
    • 通常程式都只從fd=0中讀資料,所以當n不等于0時,需要多做一步操作3<file <&3,看不懂先跳過
  • &>file:這是特殊的重定向方式,表示將標準錯誤和標準輸出都重定向到file檔案中,等價于>file 2>&1
  • &>>file:這是特殊的重定向方式,表示將標準錯誤和標準輸出都追加到file檔案中,等價于>>file 2>&1

另外,經常用于輸出的一個特殊目標檔案是/dev/null,它是空設備,可以直接丟掉所有寫入它的資料,

echo www.junmajinlong.com >/dev/null
curl -I www.junmajinlong.com 2>/dev/null >/tmp/a.log

cat </etc/fstab

一個經常用的技巧是清空檔案的方式:

$ cat /dev/null >file
$ >file

區分cat <file和cat file

cat是一個命令,這個命令的源代碼中寫了一些代碼用來處理選項和引數,

cat -n /etc/fstab

cat命令開始執行后,會識別-n選項,該選項會讓cat輸出時同時輸出行號,cat同時還會識別/etc/fstab引數,cat會讀取引數指定的檔案然后輸出,

如果沒有指定cat的檔案引數,則cat默認會從標準輸入中讀取資料,默認的標準輸入是終端,所以在沒有改變標準輸入的流向時,會從終端讀取資料,也就是用戶輸入什么字符,就讀取什么字符,然后輸出什么字符:

$ cat
junmajinlong   # 在終端輸入
junmajinlong   # 在終端輸出
junma   # 在終端輸入
junma   # 在終端輸出
^C

但用戶可以改變標準輸入的來源,比如:

$ cat </etc/fstab

表示將標準輸入來源改為/etc/fstab檔案,于是cat會從/etc/fstab中讀取資料,

另外,約定俗成的,會使用一個-來表示標準輸入或標準輸出,

# 下面是等價的,都表示從標準輸入中讀取資料
cat -
cat /dev/stdin
cat

注:這并非是一貫正確的,只是約定俗成的大多數程式的代碼中都定義了-相關的代碼處理,可參考相關命令的man手冊,如man cat中有一行:

With no FILE, or when FILE is -, read standard input.

here doc

輸入重定向是<,除此之外還有<<、<<<

<<符號表示here doc,也就是說,它后面跟的是一篇檔案,就像一個檔案一樣,只不過這個檔案的內容是臨時定義在<<符號后的,here doc常用于指定多行資料輸入,

既然是檔案,就有檔案起始符號表示檔案從此開始和檔案終止符號表示檔案到此結束,起始符和終止符中間的內容全部是檔案內容,檔案內容會作為標準輸入的資料被讀取,

檔案的起始符和終止符可以隨意定義,但兩者前后必須一樣,常見的符號是:

  • EOF:end of file
  • EOL:end of line
  • EOB:end of block

例如:

# here doc作為標準輸入被讀取,然后被cat輸出
cat <<EOF
hello
world
EOF

# here doc的內容還會被cat覆寫式輸出到指定檔案
cat <<eof >/tmp/file
hello
world
eof

# here doc的內容還會被cat追加式輸出到指定檔案
cat <<eof >>/tmp/file
hello
world
eof

# here doc和重定向符號的前后位置隨意
cat >>/tmp/file<<eof
...
eof

另外,如果將起始符用引號包圍,則不會進行變數替換、命令替換、算術替換等,如果不用引號包圍起始符,則會進行替換,

a=333
cat <<eof
$a
eof

cat <<"eof"
$a
eof

輸出結果:

333
$a

here string

<<<表示here string,也就是說該符號后面是一個字串,這個字串會作為標準輸入的內容,

cat <<<"www.junmajinlong.com"

使用單引號包圍here string時,不會進行變數替換、命令替換等,使用雙引號包圍時會進行替換,

$ a=3333
$ cat <<<$a            
3333
$ cat <<<"hello world$a"
hello world3333
$ cat <<<'hello world$a' 
hello world$a

here string常可以替代管道前的echo命令echo xxx|,例如:

# 下面是等價的
echo hello world | grep "llo"
grep "llo" <<<"hello world"

管道

管道的用法:

cmd1 | cmd2 | cmd3...

每個豎線代表一個管道,上面命令串列示cmd1的標準輸出會放進管道,cmd2會從管道中讀取進行處理,cmd2的標準輸出會放入另一個管道,cmd3會從這個管道中讀取資料進行處理,后面還可以接任意數量的管道,

Shell管道是Shell中最值得稱贊的功能之一,它以非常簡潔的形式實作了管道的行程間通信方式,我個人認為Shell處理文本資料的半壁江山都來自于豎線形式的管道,像其它編程語言,打開管道后還要區分哪個行程寫管道、哪個行程讀管道,為了安全,每個行程還要關閉不用的讀端或寫端,總之就是麻煩,而Shell的管道非常簡潔,豎線左邊的就是寫管道的,豎線右邊的就是讀管道的,

例如:

ps aux | grep 'sshd'

ps命令產生的資料(標準輸出)會寫進管道,只要管道內一有資料,grep命令就從中讀取資料進行處理,

那下面的命令中,grep從哪讀資料呢?

ps aux | grep '#' /etc/fstab

那想要讓grep既從/etc/fstab讀取資料,也從管道中讀取資料呢?

ps aux | grep '#' /etc/fstab /etc/stdin
ps aux | grep '#' /etc/fstab -

tee命令

tee命令可將一份標準輸入原樣拷貝到標準輸出和0或多個檔案中,換句話說,tee的作用是資料多重定向,

NAME
    tee - read from standard input and write to standard output and files

SYNOPSIS
    tee [OPTION]... [FILE]...

DESCRIPTION
    Copy standard input to each FILE, and also to standard output.

    -a, --append
        ppend to the given FILEs, do not overwrite

如圖:

1581130562081

例如:

$ echo hello world | tee /tmp/file1 /tmp/file2 | cat
$ echo hello world | tee -a /tmp/file3 >/dev/null

行程替換

Bash還支持行程替換(注:有些Shell不支持行程替換),

行程替換的語法:

<(cmd)
>(cmd)

行程替換和命令替換類似,都是讓cmd命令先執行,因為它們都是在Shell決議命令列的階段執行的,

行程替換先讓cmd放入后臺異步執行,并且不會等待cmd執行完,

其實,每個行程替換都是一個虛擬檔案,只不過這個檔案的內容是由cmd命令產生的(<(cmd))或被cmd命令讀取的(>(cmd)),

$ echo <(echo www.junmajinlong.com)
/dev/fd/63

既然行程替換是檔案,那么它就可以像檔案一樣被操作,比如被讀取、被當作標準輸入重定向的資料源等等:

# cmd做資料產生者
$ cat <(echo www.junmajinlong.com)   # 等價于cat /dev/fd/63
$ cat < <(echo www.junmajinlong.com) # 等價于cat </dev/fd/63

# cmd做資料接收者
$ echo hello world > >(grep 'llo')
$ echo hello world | tee >(grep 'llo') >(grep 'rld') >/dev/null

條件測驗陳述句

test命令或功能等價的Bash內置命令[ ]可以做條件測驗,如果測驗的結果為True,則退出狀態碼為0,

此外,還可以使用[[]]來做條件測驗,甚至let、$[]、$(())也可以做條件測驗,但這里暫不介紹,

這些條件測驗常用在if、while陳述句中,也常用在cmd1 && cmd2 || cmd3格式的命令列中,

用法示例:

sh_file=test.sh
[ -x "$sh_file" ] && ./$sh_file || { echo "can't execute,exit...";exit 1; }
test -x "$sh_file" && ./$sh_file || { echo "can't execute,exit...";exit 1; }

[]中的條件測驗需要和開閉中括號使用空格隔開,否則語法決議錯誤,

無測驗內容

[  ]
test

沒有任何測驗內容時,直接回傳false,

true和false命令

true命令直接回傳true,即退出狀態碼為0,

false命令直接回傳false,即退出狀態碼非0,

$ true
$ echo $?  # 0
$ false
$ echo $?  # 1

檔案類測驗

條件運算式 含義
-e file 檔案是否存在(exist)
-f file 檔案是否存在且為普通檔案(file)
-d file 檔案是否存在且為目錄(directory)
-b file 檔案是否存在且為塊設備block device
-c file 檔案是否存在且為字符設備character device
-S file 檔案是否存在且為套接字檔案Socket
-p file 檔案是否存在且為命名管道檔案FIFO(pipe)
-L file 檔案是否存在且是一個鏈接檔案(Link)

檔案屬性類測驗

條件運算式 含義
-r file 檔案是否存在且當前用戶可讀
-w file 檔案是否存在且當前用戶可寫
-x file 檔案是否存在且當前用戶可執行
-s file 檔案是否存在且大小大于0位元組,即檢測檔案是否非空檔案
-N file 檔案是否存在,且自上次read后是否被modify

兩檔案之間的比較

條件運算式 含義
file1 -nt file2 (newer than)判斷file1是否比file2新
file1 -ot file2 (older than)判斷file1是否比file2舊
file1 -ef file2 (equal file)判斷file1與file2是否為同一檔案

數值大小比較

條件運算式 含義
int1 -eq int2 兩數值相等(equal)
int1 -ne int2 兩數值不等(not equal)
int1 -gt int2 n1大于n2(greater than)
int1 -lt int2 n1小于n2(less than)
int1 -ge int2 n1大于等于n2(greater than or equal)
int1 -le int2 n1小于等于n2(less than or equal)

字串比較

條件運算式 含義
-z str (zero)判定字串是否為空?str為空串,則true
str
-n str
判定字串是否非空?str為串,則false,注:-n可省略
str1 = str2
str1 == str2
str1和str2是否相同,相同則回傳true,"=="和"="等價
str1 != str2 str1是否不等于str2,若不等,則回傳true
str1 > str2 str1字母順序是否大于str2,若大于則回傳true
str1 < str2 str1字母順序是否小于str2,若小于則回傳true

邏輯運算子

條件運算式 含義
-a或&& (and)兩運算式同時為true時才為true,
"-a"只能在test或[]中使用,&&只能在[[]]中使用
-o或|| (or)兩運算式任何一個true則為true,
"-o"只能在test或[]中使用,||只能在[[]]中使用
! 對運算式取反
( ) 改變運算式的優先級,為了防止被shell決議,應加上反斜線轉義( )

if陳述句

if test-commands; then
  consequent-commands;
[elif more-test-commands; then
  more-consequents;]
[else alternate-consequents;]
fi

test-commands既可以是test測驗或[]、[[]]測驗,也可以是任何其它命令,test-commands用于條件測驗,它只判斷命令的退出狀態碼是否為0,為0則為true,

例如:

if [ "$a" ];then echo '$a' is not none;else echo '$a' undefined or empty;fi

if [ ! -d ~/.ssh ];then
  mkdir ~/.ssh
  chown -R $USER.$USER ~/.ssh
  chmod 700 ~/.ssh
fi

if grep 'junmajinlong' /etc/passwd &>/dev/null;then
  echo 'User "junmajinlong" already exists...'
elif grep 'malongshuai' /etc/passwd &>/dev/null;then
  echo 'User "malongshuai" already exists...'
else
  echo 'you should create user,exit...'
  exit 1
fi

case

case常用于確定的分支判斷,比如:

while [ ${#@} -gt 0 ];do
  case "$1" in
    start)
    	echo start;;
    stop)
    	echo stop
    	;;
    restart)
    	echo restart
    	;;
    reload | force-reload)
    	echo reload;;
    status)
    	echo status;;
    *)
    	echo $"Usage: $0 {start|stop|status|restart|reload|force-reload}"
    	exit 2
  esac
done

case用法基本要求:

  • 除最后一個分支外,每個分支都以;;結尾,否則出現分支穿透(所以;;不是必須的)
  • 分支條件可以使用通配符號
  • 分支條件中可使用豎線隔開多個條件,表示只要匹配其中之一就執行該分支
  • 最后一般會定義一個能匹配其它任意條件的默認分支,即*)

下面是為ping命令自定義設計選項的腳本:

#!/bin/bash
while [ $1 ];do
  case "$1" in 
    -c|--count)
      count=$2
      shift 2
      ;;
    -t|--timeout)
      timeout=$2
      shift 2
      ;;
    -h|--host)
      host=$2
      shift 2
      ;;
    *)
      echo "wrong options or arguments"
      exit 1
  esac
done

ping -c $count -W timeout $host

執行:

$ chmod +x ping.sh
$ ./ping.sh -c 5 -t 2 -h www.baidu.com

for回圈

有兩種for回圈結構:

# 成員測驗類語法
for i in word1 word2 ...;do cmd_list;done

# C語言for語法
for (( expr1;expr2;expr3 ));do cmd_list;done

成員測驗類的for回圈中,in關鍵字后是使用空格分隔的一個或多個元素,for回圈時,每次從in關鍵字后面取一個元素并賦值給i變數,

例如:

$ for i in 1 2 3 4;do echo $i;done
1
2
3
4
$ for i in 1 2 "3 4";do echo $i;done
1
2
3 4

C語言型的for語法中,expr1是初始化陳述句,expr2是回圈終點條件判斷陳述句,expr3是每輪回圈后執行的陳述句,一般用來更改條件判斷相關的變數,

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

while回圈

while test_cmd_list;do cmd_list;done

while回圈,開始時會測驗test_cmd_list,如果測驗的退出狀態碼為0,則執行一次回圈體陳述句cmd_list,然后再測驗test_cmd_list,一直回圈,直到測驗退出狀態碼非0,回圈退出,

例如:

let i=1,sum=0;
while [ $i -le 10 ];do 
  let sum=sum+i
  let ++i
done

還有until回圈陳述句,但在Shell中用的很少,

while回圈經常會和read命令一起使用,read是Bash的內置命令,可用來讀取檔案,通常會按行讀取:每次讀一行,

例如:

cat /etc/fstab | while read line;do
  let num+=1
  echo $num: $line
done

上面的命令列中,首先cat行程和while結構開始運行,while結構中的read命令從標準輸入中讀取,也就是從管道中讀取資料,每次讀取一行,因為管道中最初沒有資料,所以read命令被阻塞處于資料等待狀態,當cat命令讀完檔案所有資料后,將資料放入到管道中,于是read命令從管道中每次讀取一行并將所讀行賦值給變數line,然后執行回圈體,然后繼續回圈,直到read讀完所有資料,回圈退出,

但注意,管道兩邊的命令默認是在子Shell中執行的,所以其設定的變數在命令執行完成后就消失,換句話說,在父Shell中無法訪問這些變數,比如上面的num變數是在管道的while結構中設定的,除了在while中能訪問該變數,其它任何地方都無法訪問它,

如果想要訪問while中賦值的變數,就不能使用管道,如果是直接從檔案讀取,可使用輸入重定向,如果是讀取命令產生的資料,可使用行程替換,

while read line;do
  let num1+=1
  echo $num1: $line
done </etc/fstab
echo $num1

while read line;do
  let num2+=1
  echo $num2: $line
done < <(grep 'UUID' /etc/fstab)

Shell函式

Shell函式可以當作命令一樣執行,它是一個或多個命令的組合結構體,通常,可以為每個功能定義一個函式,該函式中包含實作這個功能相關的所有命令和邏輯,

因為可以組合多個命令,并且定義之后就可以直接在當前Shell中呼叫,所以函式具有一次定義多次呼叫且代碼復用的功能,

Shell函式的定義風格有下面幾種:

function func_name {CMD_LIST}
func_name() {CMD_LIST}
function func_name() {CMD_LIST}

函式定義后,可以直接使用函式名來呼叫函式,同時還可以向函式傳遞零個或多個引數,

# 不傳遞引數
func_name
# 傳遞多個引數
func_name arg1 arg2 arg3

在函式中,那些位置變數將有特殊的意義:

  • $1、$2、$3...:傳遞給函式的第一個引數保存在$1中,第二個引數保存在$2中...
  • $@$*:保存了所有引數,各引數使用空格分隔
    • 不用雙引號包圍時,兩者沒區別
    • 雙引號包圍時,$@的各個元素都被雙引號包圍,$*的所有元素一次性被雙引號包圍

例如,定義一個函式專門用來設定和代理相關的變數:

proxy_addr=127.0.0.1:8118
function proxy_set {
  local p_addr=$1
  export http_proxy=$p_addr
  export https_proxy=$p_addr
  export ftp_proxy=$p_addr
}

# 呼叫函式
proxy_set $proxy_addr

# 各代理變數已設定
echo $http_proxy
echo $https_proxy
echo $ftp_proxy

上面在函式定義的代碼中使用了local,它可以用在函式內部表示定義一個區域變數,區域變數在函式執行完畢后就消失,不會影響函式外部的環境,

另外,函式中可以使用return陳述句來定義函式的回傳值,每當執行到函式內的return時,函式就會終止執行,直接退出函式,在Shell中,函式的回傳值其實就是退出狀態碼,

return [N]

如果不指定N,則默認退出狀態碼為0,

例如:

function sayhello {
  [ "$1" ] || { echo "give me a name please!"; return 1; }
  echo hello $1
}

sayhello "junma" ; echo $?
sayhello "jinlong" ; echo $?
sayhello ; echo $?

轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/140819.html

標籤:Linux

上一篇:使用Apache服務器實作Nginx反向代理

下一篇:Centos8(Liunx) 中安裝PHP7.4 的三種方法和洗掉它的三種方法

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • CA和證書

    1、在 CentOS7 中使用 gpg 創建 RSA 非對稱密鑰對 gpg --gen-key #Centos上生成公鑰/密鑰對(存放在家目錄.gnupg/) 2、將 CentOS7 匯出的公鑰,拷貝到 CentOS8 中,在 CentOS8 中使用 CentOS7 的公鑰加密一個檔案 gpg -a ......

    uj5u.com 2020-09-10 00:09:53 more
  • Kubernetes K8S之資源控制器Job和CronJob詳解

    Kubernetes的資源控制器Job和CronJob詳解與示例 ......

    uj5u.com 2020-09-10 00:10:45 more
  • VMware下安裝CentOS

    VMware下安裝CentOS 一、軟硬體準備 1 Centos鏡像準備 1.1 CentOS鏡像下載地址 下載地址 1.2 CentOS鏡像下載程序 點擊下載地址進入如下圖的網站,選擇需要下載的版本,這里選擇的是Centos8,點擊如圖所示。 決定選擇Centos8后,選擇想要的鏡像源進行下載,此 ......

    uj5u.com 2020-09-10 00:12:10 more
  • 如何使用Grep命令查找多個字串

    如何使用Grep 命令查找多個字串 大家好,我是良許! 今天向大家介紹一個非常有用的技巧,那就是使用 grep 命令查找多個字串。 簡單介紹一下,grep 命令可以理解為是一個功能強大的命令列工具,可以用它在一個或多個輸入檔案中搜索與正則運算式相匹配的文本,然后再將每個匹配的文本用標準輸出的格式 ......

    uj5u.com 2020-09-10 00:12:28 more
  • git配置http代理

    git配置http代理 經常遇到克隆 github 慢的問題,這里記錄一下幾種配置 git 代理的方法,解決 clone github 過慢。 目錄 git配置代理 git單獨配置github代理 git配置全域代理 配置終端環境變數 git配置代理 主要使用 git config 命令 git單獨 ......

    uj5u.com 2020-09-10 00:12:33 more
  • Linux npm install 裝包時提示Error EACCES permission denied解

    npm install 裝包時提示Error EACCES permission denied解決辦法 ......

    uj5u.com 2020-09-10 00:12:53 more
  • Centos 7下安裝nginx,使用yum install nginx,提示沒有可用的軟體包

    Centos 7下安裝nginx,使用yum install nginx,提示沒有可用的軟體包。 18 (flaskApi) [root@67 flaskDemo]# yum -y install nginx 19 已加載插件:fastestmirror, langpacks 20 Loading ......

    uj5u.com 2020-09-10 00:13:13 more
  • Linux查看服務器暴力破解ssh IP

    在公網的服務器上經常遇到別人爆破你服務器的22埠,用來挖礦或者干其他嘿嘿嘿的事情~ 這種情況下正確的做法是: 修改默認ssh的22埠 使用設定密鑰登錄或者白名單ip登錄 建議服務器密碼為復雜密碼 創建普通用戶登錄服務器(root權限過大) 建立堡壘機,實作統一管理服務器 統計爆破IP [root ......

    uj5u.com 2020-09-10 00:13:17 more
  • CentOS 7系統常見快捷鍵操作方式

    Linux系統中一些常見的快捷方式,可有效提高操作效率,在某些時刻也能避免操作失誤帶來的問題。 ......

    uj5u.com 2020-09-10 00:13:31 more
  • CentOS 7作業系統目錄結構介紹

    作業系統存在著大量的資料檔案資訊,相應檔案資訊會存在于系統相應目錄中,為了更好的管理資料資訊,會將系統進行一些目錄規劃,不同目錄存放不同的資源。 ......

    uj5u.com 2020-09-10 00:13:35 more
最新发布
  • vim的常用命令

    Vim的6種基本模式 1. 普通模式在普通模式中,用的編輯器命令,比如移動游標,洗掉文本等等。這也是Vim啟動后的默認模式。這正好和許多新用戶期待的操作方式相反(大多數編輯器默認模式為插入模式)。 2. 插入模式在這個模式中,大多數按鍵都會向文本緩沖中插入文本。大多數新用戶希望文本編輯器編輯程序中一 ......

    uj5u.com 2023-04-20 08:43:21 more
  • vim的常用命令

    Vim的6種基本模式 1. 普通模式在普通模式中,用的編輯器命令,比如移動游標,洗掉文本等等。這也是Vim啟動后的默認模式。這正好和許多新用戶期待的操作方式相反(大多數編輯器默認模式為插入模式)。 2. 插入模式在這個模式中,大多數按鍵都會向文本緩沖中插入文本。大多數新用戶希望文本編輯器編輯程序中一 ......

    uj5u.com 2023-04-20 08:42:36 more
  • docker學習

    ###Docker概述 真實專案部署環境可能非常復雜,傳統發布專案一個只需要一個jar包,運行環境需要單獨部署。而通過Docker可將jar包和相關環境(如jdk,redis,Hadoop...)等打包到docker鏡像里,將鏡像發布到Docker倉庫,部署時下載發布的鏡像,直接運行發布的鏡像即可。 ......

    uj5u.com 2023-04-19 09:26:53 more
  • 設定Windows主機的瀏覽器為wls2的默認瀏覽器

    這里以Chrome為例。 1. 準備作業 wsl是可以使用Windows主機上安裝的exe程式,出于安全考慮,默認情況下改功能是無法使用。要使用的話,終端需要以管理員權限啟動。 我這里以Windows Terminal為例,介紹如何默認使用管理員權限打開終端,具體操作如下圖所示: 2. 操作 wsl ......

    uj5u.com 2023-04-19 09:25:49 more
  • docker學習

    ###Docker概述 真實專案部署環境可能非常復雜,傳統發布專案一個只需要一個jar包,運行環境需要單獨部署。而通過Docker可將jar包和相關環境(如jdk,redis,Hadoop...)等打包到docker鏡像里,將鏡像發布到Docker倉庫,部署時下載發布的鏡像,直接運行發布的鏡像即可。 ......

    uj5u.com 2023-04-19 09:19:04 more
  • Linux學習筆記

    IP地址和主機名 IP地址 ifconfig可以用來查詢本機的IP地址,如果不能使用,可以通過install net-tools安裝。 Centos系統下ens33表示主網卡;inet后表示IP地址;lo表示本地回環網卡; 127.0.0.1表示代指本機;0.0.0.0可以用于代指本機,同時在放行設 ......

    uj5u.com 2023-04-18 06:52:01 more
  • 解決linux系統的kdump服務無法啟動的問題

    問題:專案麒麟系統服務器的kdump服務無法啟動,沒有相關日志無法定位問題。 1、查看服務狀態是關閉的,重啟系統也無法啟動 systemctl status kdump 2、修改grub引數,修改“crashkernel”為“512M(有的機器數值太大太小都會導致報錯,建議從128M開始試,或者加個 ......

    uj5u.com 2023-04-12 09:59:50 more
  • 解決linux系統的kdump服務無法啟動的問題

    問題:專案麒麟系統服務器的kdump服務無法啟動,沒有相關日志無法定位問題。 1、查看服務狀態是關閉的,重啟系統也無法啟動 systemctl status kdump 2、修改grub引數,修改“crashkernel”為“512M(有的機器數值太大太小都會導致報錯,建議從128M開始試,或者加個 ......

    uj5u.com 2023-04-12 09:59:01 more
  • 你是不是暴露了?

    作者:袁首京 原創文章,轉載時請保留此宣告,并給出原文連接。 如果您是計算機相關從業人員,那么應該經歷不止一次網路安全專項檢查了,你肯定是收到過資訊系統技術檢測報告,要求你加強風險監測,確保你提供的系統服務堅實可靠了。 沒檢測到問題還好,檢測到問題的話,有些處理起來還是挺麻煩的,尤其是線上正在運行的 ......

    uj5u.com 2023-04-05 16:52:56 more
  • 細節拉滿,80 張圖帶你一步一步推演 slab 記憶體池的設計與實作

    1. 前文回顧 在之前的幾篇記憶體管理系列文章中,筆者帶大家從宏觀角度完整地梳理了一遍 Linux 記憶體分配的整個鏈路,本文的主題依然是記憶體分配,這一次我們會從微觀的角度來探秘一下 Linux 內核中用于零散小記憶體塊分配的記憶體池 —— slab 分配器。 在本小節中,筆者還是按照以往的風格先帶大家簡單 ......

    uj5u.com 2023-04-05 16:44:11 more