1. 程式人生 > >第九章、shell腳本編程基礎

第九章、shell腳本編程基礎

perl 大小 news 機器碼 局部變量 word enter 類型 nal

第九章、shell腳本編程基礎

本章內容

  • 編程基礎
  • 腳本基本格式
  • 變量
  • 運算
  • 條件測試
  • 配置用戶環境

編程基礎

  • 程序:指令+數據
  • 程序編程風格:

過程式:以指令為中心,數據服務於指令

對象式:以數據為中心,指令服務於數據

  • shell程序:提供了編程能力,解釋執行

程序的執行方式

  • 計算機:運行二進制指令
  • 編程語言:

低級:匯編

高級:

編譯:高級語言-->編譯器-->目標代碼

java,C#

解釋:高級語言-->解釋器-->機器代碼

shell, perl, python

(系統後臺有個解釋器,直接將語言轉化為機器碼,放到內存中直接運行)

編程基本概念

  • 編程邏輯處理方式:

順序執行

循環執行

選擇執行

  • shell編程:過程式、解釋執行

編程語言的基本結構:

各種系統命令的組合

數據存儲:變量、數組

表達式: a + b

語句:if

shell腳本基礎

  • shell腳本:

包含一些命令或聲明,並符合一定格式的文本文件

  • 格式要求:首行shebang機制

#!/bin/bash(告訴系統是哪種shell語法)

#!/usr/bin/python

#!/usr/bin/perl

  • shell腳本的用途有:

自動化常用命令(三次命令以上,推薦使用腳本)

執行系統管理和故障排除

創建簡單的應用程序

處理文本或文件

創建shell腳本

  • 第一步:使用文本編輯器來創建文本文件

第一行必須包括shell聲明序列:#!

#!/bin/bash

添加註釋

註釋以#開頭

  • 第二步:運行腳本

給予執行權限,在命令行上指定腳本的絕對或相對路徑

直接運行解釋器,將腳本作為解釋器程序的參數運行

腳本規範

  • 腳本代碼開頭約定

1、第一行一般為調用使用的語言

2、程序名,避免更改文件名為無法找到正確的文件

3、版本號

4、更改後的時間

5、作者相關信息

6、該程序的作用,及註意事項

7、最後是各版本的更新簡要說明

腳本的基本結構

  • 腳本的基本結構

#!SHEBANG

CONFIGURATION_VARIABLES

FUNCTION_DEFINITIONS

MAIN_CODE

  • shell腳本示例

#!/bin/bash

# ------------------------------------------

# Filename: hello.sh

# Revision: 1.1

# Date: 2017/11/22

# Author: sunan

# Email: [email protected]

# Website: www.sunanblog.com

# Description: This is the first script

# ------------------------------------------

# Copyright: 2017 sunan

# License: GPL

echo “hello shell”

腳本調試

  • 檢測腳本中的語法錯誤

bash -n /path/to/some_script(檢查語法錯誤,不檢查命令錯誤)

  • 調試執行

bash -x /path/to/some_script(檢查語法和命令錯誤)

變量

  • 變量:命名的內存空間

數據存儲方式:

字符:

數值:整型,浮點型

  • 變量:變量類型

作用:

1、數據存儲格式

2、參與的運算

3、表示的數據範圍

類型:

字符

數值:整型、浮點型

  • 強類型:變量不經過強制轉換,它永遠是這個數據類型,不允許隱式的類型轉換。一般定義變量時必須指定類型、參與運算必須符合類型要求;調用未聲明變量會產生錯誤

如 java,c#

  • 弱類型:語言的運行時會隱式做數據類型轉換。無須指定類型,默認均為字符型;參與運算會自動進行隱式類型轉換;變量無須事先定義可直接調用

如:bash 不支持浮點數,php

  • 變量命名法則:

1、不能使程序中的保留字:例如if, for

2、只能使用數字、字母及下劃線,且不能以數字開頭

3、見名知義

4、統一命名規則:小駝峰命名法和大駝峰命名法

例如:firstFunctionName( )(小駝峰命名法)

FirstClassName( ) (大駝峰命名法)

bash中變量的種類

  • 根據變量的生效範圍等標準劃分下面變量類型:

局部變量:生效範圍為當前shell進程;對當前shell之外的其它shell進程,包括當前shell的子shell進程均無效(如何查看當前的shell屬於哪個bash進程,見附錄1)

環境(全局)變量:生效範圍為當前shell進程及其子進程

本地變量:生效範圍為當前shell進程中某代碼片斷,通常指函數

位置變量:$1, $2, ...來表示,用於讓腳本在腳本代碼中調用通過命令行傳遞給它的參數

特殊變量:$?, $0, $*, $@, $#,$$

局部變量

  • 變量賦值:name=‘value’(=兩邊不要加空格)

將變量賦兩遍值,不是將原來空間的值覆蓋,而是新開辟一個空間進行賦值,

變量指向新的空間值,而原來的空間閑置並被別的賦值覆蓋。(2.66)

  • 可以使用引用value:

(1) 可以是直接字串; name=“root"

(2) 變量引用:name="$USER"

(3) 命令引用:name=`COMMAND` name=$(COMMAND)

  • 變量引用:${name} $name

"":弱引用,其中的變量引用會被替換為變量值

‘‘:強引用,其中的變量引用不會被替換為變量值,而保持原字符串

  • 顯示已定義的所有變量:set
  • 刪除變量:unset name

環境變量

  • 變量聲明、賦值:

export name=VALUE

declare -x name=VALUE

環境變量賦予的值可以傳遞給子進程,但子進程修改環境變量的值只能往下傳遞,不能影響父進程的值。(詳見附錄1.2)

  • 變量引用:$name, ${name}(其中腳本中調用參數超過10使用${name},因為腳本中$10 =$1+0)
  • 顯示所有環境變量:

env

printenv

export

declare -x

  • 刪除變量:

unset name

  • bash內建的環境變量:

?PATH

?SHELL

?USER

?UID

?HOME

?PWD

?SHLVL(查看shell嵌套深度,詳見附錄1.3)

?LANG

?MAIL

?HOSTNAME

?HISTSIZE

?_(下劃線,上一條命令的參數)

只讀和位置變量

  • 只讀變量:只能聲明,但不能修改和刪除

聲明只讀變量:

readonly name

declare -r name

查看只讀變量:

readonly –p

  • 位置變量:在腳本代碼中調用通過命令行傳遞給腳本的參數

$1, $2, ...:對應第1、第2等參數,shift [n]換位置(往前移動幾個位置,詳見1.6)

$0: 命令本身

$*: 傳遞給腳本的所有參數,全部參數合為一個字符串

$@: 傳遞給腳本的所有參數,每個參數為獨立字符串

$#: 傳遞給腳本的參數的個數

$@ $* 只在被雙引號包起來的時候才會有差異

set -- 清空所有位置變量

(4.10)

退出狀態

  • 進程使用退出狀態來報告成功或失敗

0 代表成功,1-255代表失敗

  • $? 變量保存最近的命令退出狀態

例如:

ping -c1 -W1 hostdown &> /dev/null

echo $?

退出狀態碼

  • bash自定義退出狀態碼

exit [n]:自定義退出狀態碼

註意:腳本中一旦遇到exit命令,腳本會立即終止;終止退出狀態取決於exit命令後面的數字

註意:如果未給腳本指定退出狀態碼,整個腳本的退出狀態碼取決於腳本中執行的最後一條命令的狀態碼

算術運算

  • bash中的算術運算:help let

+, -, *, /, %取模(取余), **(乘方)

實現算術運算:

(1) let var=算術表達式

(2) var=$[算術表達式]

(3) var=$((算術表達式))

(4) var=$(expr arg1 arg2 arg3 ...)(詳見1.9)

(5) declare –i var = 數值

(6) echo ‘算術表達式’ | bc

  • 乘法符號有些場景中需要轉義,如*
  • bash有內建的隨機數生成器:$RANDOM(0-32767)

echo $[$RANDOM%50] :0-49之間隨機數

賦值

  • 增強型賦值:

+=, -=, *=, /=, %=

  • let varOPERvalue

例如:let count+=3

自加3後自賦值

  • 自增,自減:

let var+=1

let var++

let var-=1

let var--

邏輯運算

  • true, false

1, 0

  • 與:

1 與 1 = 1

1 與 0 = 0

0 與 1 = 0

0 與 0 = 0

  • 或:

1 或 1 = 1

1 或 0 = 1

0 或 1 = 1

0 或 0 = 0

  • 非:!

! 1 = 0

! 0 = 1

  • 短路運算

短路與

第一個為0,結果必定為0

第一個為1,第二個必須要參與運算

短路或

第一個為1,結果必定為1

第一個為0,第二個必須要參與運算

  • 異或:^

異或的兩個值,相同為假,不同為真

條件測試

  • 判斷某需求是否滿足,需要由測試機制來實現

專用的測試表達式需要由測試命令輔助完成測試過程

  • 評估布爾聲明,以便用在條件性執行中

若真,則返回0

若假,則返回1

  • 測試命令:

test EXPRESSION

[ EXPRESSION ]

[[ EXPRESSION ]]

註意:EXPRESSION前後必須有空白字符

=~後正則表達式不要加引號

字符串匹配加引號

條件性的執行操作符

  • 根據退出狀態而定,命令可以有條件地運行

&& 代表條件性的AND THEN

|| 代表條件性的OR ELSE

例如:

grep -q no_such_user /etc/passwd \

|| echo ‘No such user‘

No such user

ping -c1 -W2 station1 &> /dev/null \

> && echo "station1 is up" \

> || (echo ‘station1 is unreachable‘; exit 1)

station1 is up

test命令

  • 長格式的例子:

test "$A" == "$B" && echo "Strings are equal"

test “$A” -eq “$B” && echo "Integers are equal"

  • 簡寫格式的例子:

[ "$A" == "$B" ] && echo "Strings are equal"

[ "$A" -eq "$B" ] && echo "Integers are equal"

建議使用簡寫格式,註意[ 和單詞之間有空格。

[ ]裏面有東西就為真,但是要用” “把變量引起來才知道有東西。(詳見1.12)

bash的數值測試

  • -v VAR

變量VAR是否設置(詳見附錄1.12)

  • 數值測試:(判斷數字大小,兩邊必須都是數字)

-gt 是否大於

-ge 是否大於等於

-eq 是否等於

-ne 是否不等於

-lt 是否小於

-le 是否小於等於

bash的字符串測試

  • 字符串測試:

== 是否等於

> ascii碼是否大於ascii碼

< 是否小於

!= 是否不等於

=~ 左側字符串是否能夠被右側的PATTERN(正則表達式)所匹配(左側能否包含右側)正則表達式中變量加引號,字符串不加引號。(詳見附錄1.13)

註意: 此表達式一般用於[[ ]]中;擴展的正則表達式

[[]]中判斷字符串是否相等用==,[]判斷字符串是否相等用一個=即可,==也行。這種判斷一般一個中括號就行了,兩個中括號用於支持正則表達式。

-z "STRING“ 字符串是否為空,空為真,不空為假

-n "STRING“ 字符串是否不空,不空為真,空為假(詳見附錄1.12)

註意:用於字符串比較時的用到的操作數都應該使用引號

Bash的文件測試

  • 存在性測試

-a FILE:同-e

-e FILE: 文件存在性測試,存在為真,否則為假

  • 存在性及類別測試

-b FILE:是否存在且為塊設備文件

-c FILE:是否存在且為字符設備文件

-d FILE:是否存在且為目錄文件

-f FILE:是否存在且為普通文件

-h FILE 或 -L FILE:存在且為符號鏈接文件(詳見附錄1.15)

-p FILE:是否存在且為命名管道文件

-S FILE:是否存在且為套接字文件

Bash的文件權限測試

  • 文件權限測試:

-r FILE:是否存在且可讀

-w FILE: 是否存在且可寫

  • -x FILE: 是否存在且可執行(詳見附錄1.16)
  • 文件特殊權限測試:

-u FILE:是否存在且擁有suid權限

-g FILE:是否存在且擁有sgid權限

-k FILE:是否存在且擁有sticky權限

Bash的文件屬性測試

  • 文件大小測試:

-s FILE: 是否存在且非空

  • 文件是否打開:

-t fd: fd 文件描述符是否在某終端已經打開(詳見附錄1.14)

-N FILE:文件自從上一次被讀取之後是否被修改過

-O FILE:當前有效用戶是否為文件屬主

-G FILE:當前有效用戶是否為文件屬組

(當前有效用戶和實際用戶不一定是同一個人,像當前用戶執行passwd,當前實際執行的是root權限,當時有效用戶變成了root,實際用戶是當前用戶)

  • 雙目測試:

FILE1 -ef FILE2: FILE1是否是FILE2的硬鏈接

FILE1 -nt FILE2: FILE1是否新於FILE2(mtime)

FILE1 -ot FILE2: FILE1是否舊於FILE2

Bash的組合測試條件

  • 第一種方式:

COMMAND1 && COMMAND2 並且

COMMAND1 || COMMAND2 或者

! COMMAND 非

如:[[ -r FILE ]] && [[ -w FILE ]]

  • 第二種方式:

EXPRESSION1 -a EXPRESSION2 並且

EXPRESSION1 -o EXPRESSION2 或者

! EXPRESSION

必須使用測試命令進行

示例:

[ -z “$HOSTNAME” -o $HOSTNAME "==\

"localhost.localdomain" ] && hostname www.magedu.com

[ -f /bin/cat -a -x /bin/cat ] && cat /etc/fstab

使用read命令來接受輸入

  • 使用read來把輸入值分配給一個或多個shell變量

-p 指定要顯示的提示

-s 靜默輸入,一般用於密碼

-n N 指定輸入的字符長度N

-d ‘字符’ 輸入結束符

-t N TIMEOUT為N秒

read 從標準輸入中讀取值,給每個單詞分配一個變量

所有剩余單詞都被分配給最後一個變量

read -p “Enter a filename: “ FILE

bash如何展開命令行

(命令運行的過程)

  • 把命令行分成單個命令詞
  • 展開別名

(在腳本中別名不能使用)

  • 展開大括號的聲明({})

echo {1..6}

1 2 3 4 5 6

  • 展開波浪符聲明(~)

家目錄

  • 命令替換$() 和 ``)
  • 再次把命令行分成命令詞
  • 展開文件通配(*、?、[abc]等等)
  • 準備I/0重導向(<、>)
  • 運行命令

上面的執行順序說明的執行的優先級

防止擴展

  • 反斜線(\)會使隨後的字符按原意解釋

$ echo Your cost: \$5.00

$本身是表示變量的開始符,要原意顯示要加\

Your cost: $5.00

  • 加引號來防止擴展

單引號(’)防止所有擴展

雙引號(”)也防止所有擴展,但是以下情況例外:

$(美元符號) - 變量擴展

`(反引號) - 命令替換

\(反斜線) - 禁止單個字符擴展

!(嘆號) - 歷史命令替換

bash的配置文件

  • 按生效範圍劃分,存在兩類:

?全局配置:

/etc/profile

/etc/profile.d/*.sh

/etc/bashrc

? 個人配置:

~/.bash_profile

~/.bashrc

shell登錄兩種方式

  • 交互式登錄:

(1)直接通過終端輸入賬號密碼登錄

(2)使用“su - UserName” 切換的用戶

執行順序:/etc/profile --> /etc/profile.d/*.sh --> ~/.bash_profile --> ~/.bashrc --> /etc/bashrc

  • 非交互式登錄:

(1)su UserName

(2)圖形界面下打開的終端

(3)執行腳本

(4)任何其它的bash實例

執行順序: ~/.bashrc --> /etc/bashrc --> /etc/profile.d/*.sh

上面的執行順序:在文件中調用的先後順序。

Profile類

  • 按功能劃分,存在兩類:

profile類和bashrc類

  • profile類:為交互式登錄的shell提供配置

全局:/etc/profile, /etc/profile.d/*.sh

個人:~/.bash_profile

功用:

(1) 用於定義環境變量

(2) 運行命令或腳本

Bashrc類

  • bashrc類:為非交互式和交互式登錄的shell提供配置

全局:/etc/bashrc

個人:~/.bashrc

功用:

(1) 定義命令別名和函數

(2) 定義本地變量

編輯配置文件生效

  • 修改profile和bashrc文件後需生效

兩種方法:

1重新啟動shell進程

2 . 或source

例:

. ~/.bashrc

執行腳本盡量不要使用.或source執行,因為會將原來bash中的相同變量值改變,而用bash或./filename會新開一個bash進程,執行完就退出,不會改變原來的變量值。

Bash 退出任務

  • 保存在~/.bash_logout文件中(用戶)
  • 在退出登錄shell時運行
  • 用於

創建自動備份

清除臨時文件

可以在腳本寫上退出時要執行的操作。

上面的所有配置文件生效,都必須是需要用戶登錄,不登錄就無法讀取配置文件內容。要想不登錄執行,就要把文件寫入到開機啟動的內核中了。

$-變量

  • h:hashall,打開這個選項後,Shell 會將命令所在的路徑hash下來,避免每次都要查詢。通過set +h將h選項關閉
  • i:interactive-comments,包含這個選項說明當前的 shell 是一個交互式的 shell。所謂的交互式shell,在腳本中,i選項是關閉的。
  • m:monitor,打開監控模式,就可以通過Job control來控制進程的停止、繼續,後臺或者前臺執行等。
  • B:braceexpand,大括號擴展
  • H:history,H選項打開,可以展開歷史列表中的命令,可以通過!感嘆號來完成,例如“!!”返回上最近的一個歷史命令,“!n”返回第 n 個歷史命令
  • (詳見附錄1.18)

附錄:

1.1 進程樹

[root@centos7 ~]#ps aux

USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND

root 2058 0.0 0.2 147788 2360 ? Rs 08:14 0:04 sshd: root@pts/0

root 2062 0.0 0.2 116292 2796 pts/0 Ss 08:15 0:00 -bash

root 5191 0.0 0.0 107904 612 ? S 11:15 0:00 sleep 60

root 5198 0.0 0.1 151064 1804 pts/0 R+ 11:15 0:00 ps aux

……

查看所有的進程信息

[root@centos7 ~]#echo $$

2062

查看當前的進程編號

[root@centos7 ~]#pstree -p

├─smartd(591)

├─sshd(1013)───sshd(2058)───bash(2062)───pstree(5319)

├─systemd-journal(357)

├─systemd-logind(600)

查看當前的進程樹子進程和父進程信息,可以看到pstree是bash的子進程,運行pstree命令,會用bash程序會去解釋執行命令

[root@centos7 ~]#bash

[root@centos7 ~]#echo $$

5498

當前進程號

bash下面bash,bash的子進程bash

[root@centos7 ~]#echo $PPID

2062

查看父進程編號

[root@centos7 ~]#echo $$

2553

[root@centos7 ~]#exit

exit

[root@centos7 ~]#echo $$

2039

退出當前進程使用exit命令

[root@centos7 ~]#name=`cat /etc/issue`

[root@centos7 ~]#echo $name

The hostname is \n Time is \t TTY is \l \S Kernel \r on an \m

[root@centos7 ~]#echo "$name"

The hostname is \n

Time is \t

TTY is \l

\S

Kernel \r on an \m

變量是一個很長的文章,需要將變量加上雙引號才能按原格式輸出

1.2 環境變量

[root@centos7 ~]#export var=100

[root@centos7 ~]#echo $var

100

[root@centos7 ~]#bash

[root@centos7 ~]#echo $var

100

[root@centos7 ~]#var=200

[root@centos7 ~]#bash

[root@centos7 ~]#echo $var

200

[root@centos7 ~]#exit

exit

[root@centos7 ~]#exit

exit

[root@centos7 ~]#echo $var

100

可以看出環境變量的賦值只能向下傳遞,不能向上傳遞。

1.3 shell嵌套深度

[root@centos7 ~]#echo $SHLVL

1

[root@centos7 ~]#bash

[root@centos7 ~]#echo $SHLVL

2

[root@centos7 ~]#bash

[root@centos7 ~]#echo $SHLVL

3

查看shell的嵌套深度

1.4 ( )開啟新的bash

[root@centos7 ~]#( umask 066;touch /app/ff )

[root@centos7 ~]#umask

0022

[root@centos7 ~]#ls /app

binary ff passwd scripts

命令中的小括號代表新開一個bash,運行完命令後退出新開的bash。

1.5 scp傳文件

[root@centos7 ~]#scp filename [email protected]:

上傳文件到wang的家目錄中,密碼:magedu

[root@centos7 ~]#scp -r [email protected]:/home/wang/scripts /app/

將遠程主機上的文件拷貝到本機上,-r拷貝目錄

1.6 腳本中shift作用

[root@centos7 /app/scripts]#cat f1.sh

#!/bin/bash

echo "1st is $1"

echo "2st is $2"

echo "3st is $3"

shift

echo "1st is $1"

echo "2st is $2"

echo "3st is $3"

[root@centos7 /app/scripts]#./f1.sh a b c

1st is a

2st is b

3st is c

1st is b

2st is c

3st is

使用shift參數往左移動了一位

1.7 上傳文件腳本化

[root@centos7 /app/scripts]#vim scp14.sh

#!/bin/bash

scp $* [email protected]:

上傳代碼腳本化

1.8 腳本頭自動生成

#!/bin/bash

# create script header automatically

echo "#!/bin/bash

#Filename: $1

#Author: sunan

#Date: `date +%F`

">$1

chmod +x $1

vim + $1

[root@centos7 /app/scripts]#./make_script_header.sh news.sh

腳本頭腳本化

1.9 expr計算運算符加空格

[root@centos7 /app/scripts]#expr 1+2

1+2

[root@centos7 /app/scripts]#expr 1 + 2

3

[root@centos7 /app/scripts]#expr 1 * 2

expr: syntax error

[root@centos7 /app/scripts]#expr 1 \* 2

2

expr計算需要運算符加空格,*需要轉義。

[root@centos7 /app/scripts]#expr 1 - 1

0

[root@centos7 /app/scripts]#echo $?

1

[root@centos7 /app/scripts]#expr 1 - 1

0

[root@centos7 /app/scripts]#echo $?

1

[root@centos7 /app/scripts]#let 1-1

[root@centos7 /app/scripts]#echo $?

1

上面的命令可以正確執行,但返回的執行結果不是0,man expr可以看到:

Exit status is 0 if EXPRESSION is neither null nor 0, 1 if EXPRESSION

is null or 0, 2 if EXPRESSION is syntactically invalid, and 3 if an error occurred.

1.10 字體加顏色

[root@centos7 /app/scripts]#vim color.sh

^[[31mred^[[0m

實現字體加顏色,其中的^[是在vim中使用Ctrl+v+[實現。

[root@centos7 /app/scripts]#cat color.sh

red

字體變成紅色

1.11 文件加顏色

[root@centos7 /app/scripts]#^Mcolor=$[RANDOM%7+31];echo -e "\033[${color}mred color\033[0m"

給文件加顏色

1.12 關於[ ]的判斷

[root@centos7 /app/scripts]#[ ]&& echo true || echo false

false

[root@centos7 /app/scripts]#[ 0 ]&& echo true || echo false

true

[root@centos7 /app/scripts]#[ "" ]&& echo true || echo false

false

[root@centos7 /app/scripts]#[ " " ]&& echo true || echo false

true

[root@centos7 /app/scripts]#a=111

[root@centos7 /app/scripts]#[ $a ]&& echo true || echo false

true

[root@centos7 /app/scripts]#unset a

[root@centos7 /app/scripts]#[ $a ]&& echo true || echo false

false

[root@centos7 /app/scripts]#a=" "

[root@centos7 /app/scripts]#[ $a ]&& echo true || echo false

false

[root@centos7 /app/scripts]#[ "$a" ]&& echo true || echo false

true

關於[ ]判斷執行成功條件

[root@centos7 ~]# var=hh;[ -n $var ]&&echo true || echo false

true

[root@centos7 ~]# unset var;[ -n $var ]&&echo true || echo false

true

[root@centos7 ~]# [ -n ]&&echo true || echo false

true

[root@centos7 ~]# [ -n "$var" ]&&echo true || echo false

false

當var沒有定義,但又沒加雙引號[ ]判斷相當於只有-n存在,就判斷為真。

中括號裏面當判斷的時候,要加雙引號。

[root@centos7 scripts]# vim useradd.sh

#!/bin/bash

[ $# -ne 1 ] &&echo -e "The arg must one \n Usage:useradd.sh username" && exit 10

id $1 &> /dev/null && echo "$! is exist " && exit 20

useradd $1 && echo "$! is created"

判斷用戶輸入的參數是否等於1,不是退出,是繼續下面的命令。

[root@centos7 scripts]# var="";[ -v var ]&&echo true ||echo false

true

[root@centos7 scripts]# var=ab;[ -v var ]&&echo true ||echo false

true

[root@centos7 scripts]# unset var;[ -v var ]&&echo true ||echo false

false

只要變量定義了就為真,var前面不需要加$,因為-v 的作用就是直接加var。

[root@centos7 scripts]# vim useradd.sh

#!/bin/bash

[ -n “$1”] ||{echo -e "The arg must one \n Usage:useradd.sh username" && exit 10;}

id $1 &> /dev/null && echo "$! is exist " && exit 20

useradd $1 && echo "$! is created"

-n 判斷$1是否為空,空就是假執行後面命令,非空為真,跳過後面命令執行下面命令。同時上面必須用{ },( )新開一個子shell,退出是退出一個子shell。

1.13關於[[ ]]的判斷

[root@centos7 ~]# filename=f1.sh;[[ "$filename" =~ \.sh$ ]] && echo true || echo false

true

[root@centos7 ~]# filename=f1.sh;[[ "$filename" =~ "\.sh$" ]] && echo true || echo false

false

和正則表達式做判斷時,字符串加引號被認為字符串和引號是一個整體。

[]:單中括號不支持正則表達式

[root@centos7 ~]# var="abc*";[[ "$var" == "abc*" ]]&&echo true ||echo false

true

[root@centos7 ~]# var="abc*";[[ "$var" == abc* ]]&&echo true ||echo false

true

[root@centos7 ~]# var="abcdef*";[[ "$var" == abc* ]]&&echo true ||echo false

true #把*當成通配符了

[root@centos7 ~]# var="abdef*";[[ "$var" == abc* ]]&&echo true ||echo false

false

工作中最好不要這樣用,掌握一個原則:只有用到正則表達式匹配用[[ ]],通常的匹配用[ ]即可,不然容易亂。

[root@centos7 ~]# ip=1.1.1.1;[[ "$ip" =~ ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ ]]&&echo true || echo false

true

[root@centos7 ~]# ip=1111.1.1.1;[[ "$ip" =~ ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ ]]&&echo true || echo false

false

判斷一個ip地址是否正確

[root@centos7 ~]#filename=f1.sh ; [ "$filename" =~ \.sh$ ] && echo true ||echo false

判斷後綴

[root@centos7 ~]#var=haha123 ; [[ "$var" =~ ^[0-9]+$ ]] && echo true || echo false

判斷數字

[root@centos7 ~]#var=0123 ; [[ "$var" =~ ^0*[1-9][0-9]*$ ]] && echo true || echo false

判斷正整數

[root@centos7 ~]#mobile=12800138000 ;[[ "$mobile" =~ ^1[3456789][0-9]{9}$ ]] && echo true || echo false

手機號

1.14 文件描述符

面試題:當前這個進程打開了多少個文件?

每打開一個文件就打開一個文件描述符,就是統計文件描述符的個數。

[root@centos7 scripts]# ls -l /proc/$$/fd

total 0

lrwx------. 1 root root 64 Nov 25 08:13 0 -> /dev/pts/0

lrwx------. 1 root root 64 Nov 25 08:13 1 -> /dev/pts/0

lrwx------. 1 root root 64 Nov 25 08:13 2 -> /dev/pts/0

lrwx------. 1 root root 64 Nov 25 10:30 255 -> /dev/pts/0

[root@centos7 scripts]# ls /proc/$$/fd | wc -l

4

[root@centos7 scripts]# ls -l /proc/$$/fd | wc -l

5

同時註意加 -l和不加結果不同

1.15 鏈接文件

[root@centos7 scripts]# [ -d /lib ] && echo true

true

[root@centos7 scripts]# [ -l /lib ] && echo true

-bash: [: -l: unary operator expected

[root@centos7 scripts]# [ -L /lib ] && echo true

true

判斷文件屬性,需要先判斷是不是鏈接文件,如果是鏈接文件判斷的文件屬性石,鏈接的原文件的屬性。

1.16 文件權限判斷

[root@centos7 scripts]# [ -r /etc/shadow ]&& echo true

true

[root@centos7 scripts]# [ -w /etc/shadow ]&& echo true

true

[root@centos7 scripts]# [ -x /etc/shadow ]&& echo true

[root@centos7 scripts]# ll /etc/shadow

----------. 1 root root 1197 Nov 7 17:43 /etc/shadow

判斷一個文件的權限不能只看表面的權限,要看實際的最終權限。

1.17 read

[root@centos7 scripts]# read

asdf

[root@centos7 scripts]# echo $REPLY

asdf

[root@centos7 scripts]# read name

abc

[root@centos7 scripts]# echo $name

abc

read沒有給變量,就賦給了REPLY。

[root@centos7 scripts]# read name age title

sunan 26 CTO

[root@centos7 scripts]# echo $name $age $title

sunan 26 CTO

賦予多個值,最好一個個賦值。

[root@centos7 scripts]# read -s -p "please input your password:" password

please input your password:[root@centos7 scripts]#

-s靜默模式輸入信息後看不到。

[root@localhost ~]#read -n 8 -p "please input your password:" passwd

please input your password:12345678[root@localhost ~]#

-n 規定最多輸入幾個字符,超過最多的字符數就自動退出。

1.18$-變量

[root@localhost ~]#echo $-

himBH

查看當前啟用的功能。

[root@localhost ~]#set +h

[root@localhost ~]#echo $-

imBH

去掉hash功能

[root@localhost ~]#hash

-bash: hash: hashing disabled

[root@localhost ~]#set -h

[root@localhost ~]#hash

hits command

1 /bin/cat

3 /bin/ls

set -h 恢復hash功能的使用

[root@localhost ~]#vim i.sh

#!/bin/bash

echo "$-"

[root@localhost ~]#bash i.sh

hB

在腳本中i功能是被禁用的,i交互式(像別名)。

[root@localhost ~]#echo {1..9}

1 2 3 4 5 6 7 8 9

B大括號擴展功能可以使用

練習:

不想讓別的用戶登錄:生成文件/etc/nologin

第九章、shell腳本編程基礎