Shell編程 詳解特殊變量之位置參數

今天我們來探討shell編程的特殊變量:位置變量。

首先我創建了一個testargs.sh的小腳本:

#!/usr/bin/env bash
#
# Author: jacky18676887374@aliyun.com
# date: 20160813-19:30:59
# Vervion: 0.0.1
# Description:
# Synopsis:
#
#測試腳本的位置參數
#
echo 'This is $# :>>>|'$#
echo 'This is $@ :>>>|'$@
echo 'This is $* :>>>|'$*
echo 'This is $0 :>>>|'$0
echo 'This is $1 :>>>|'$1
echo 'This is $2 :>>>|'$2
echo 'This is $3 :>>>|'$3
echo 'This is $9 :>>>|'$9
echo 'This is $10 :>>>|'$10
echo 'This is ${10} :>>>|'${10}
echo 'This is $11 :>>>|'$11
echo 'This is ${11} :>>>|'${11}
echo 'This is ${-1} :>>>|'${-1}

給腳本a-t共計20個參數,運行之:

wKioL1euxpzATMQ_AAA1W86YR2Y246.png

由實例我們可以得出初步結論:

  • 0: shell腳本的名字;

  • NN是1開始的正整數,shell腳本的第N個位置參數,當N是個位數數字,可以表示為$N;當N非個位數時候,需要 { }  ,即${N} ;

  • #:shell腳本的參數的個數,以十進制計數;

  • *:參數列表

  • @:參數列表

對于前面的三個很好理解,但是*和@都是參數列表,難道說*=@嗎?第一反應就是:這不可能,一定是個坑。

到網上查找資料,在Chet Ramey , Brian Fox 著 邵加超(Jerry Fleming)譯注的《BASH中文文檔》看到說明介紹:


wKiom1eux17jQvJEAAHPt7--rbg268.png


真對不起我的語文老師,幾遍下來,依然覺得很生澀,似懂非懂。只能動手結合實例理解:

#!/usr/bin/env bash
#
#測試腳本的位置參數: @ 和 *
#
echo 'This is $@ :>>>|'$@
echo 'This is $* :>>>|'$*

wKioL1euy4yB2pxHAAARpzT4GXc634.png

貌似看不出來個所以然,恍然想起echo命令是以行顯示內容,列表都變成一行輸出了。

看來要出大招了j_0061.gif


wKioL1euzdHi4PvgAAEwYL5o5c8922.png



思路:把參數列表傳遞給for循環的i變量,然后打印$i,

一言不合,說干就干j_0066.gif

#!/usr/bin/env bash
#
#測試腳本的位置參數: @ 和 *
#
echo 'begin testing $@......'
for i in $@
do
    echo $i
done
echo 'begin testing $*......'
for i in $*
do
    echo $i
done

wKioL1eu0Q7gtPyiAAAblavWOs8492.png

什么情況…還是一樣的,難道我的理解錯了?再來:

#!/usr/bin/env bash
#
#測試腳本的位置參數: @ 和 *
#
echo 'begin testing $@......'
for i in "$@"
do
    echo $i
done
echo 'begin testing $*......'
for i in "$*"
do
    echo $i
done

wKioL1eu0iSA_AFVAAAX39BIBpo423.png

真相浮出水面(我果然對不起語文老師)…再看一眼正確演示的腳本↓↓↓↓

wKiom1eu01CjdsEGAABFEE8b9_8724.png

由此可以得出最后結論

  • 0: shell腳本的名字;

  • NN是1開始的正整數,shell腳本的第N個位置參數,當N是個位數數字,可以表示為$N;當N非個位數時候,需要 { }  ,即${N} ;

  • #:shell腳本的參數的個數,以十進制計數;

  • *:參數列表,當"$*"時,將所有參數當成一個單位;

  • @:參數列表,當"$@"時,每個參數獨立,是多單位的列表清單。

到低腳本支持多少個參數呢?
當測試到N的時候,就忍不住想,shell腳本到低支持多少個參數呢?有什么方法驗證呢?抓耳撓腮…還是想到了個笨方法:

思路:seq命令將1..N展開做參數,給shell腳本執行。寫好腳本

[root@IP70-CentOS7 ~]# >>echo 'echo This is \$\{10\} \:\|${10}' >> testargs.sh
#往腳本追加一條顯示語句。提示位置參數是多少
[root@IP70-CentOS7 ~]# >>./testargs.sh $(seq 1 314551)
#執行腳本,參數由seq命令展開

wKiom1eu38HyVXq0AAAkjr8vFZ4487.png

看來10萬是小意思嘛…再來個0,一百萬j_0061.gif

wKioL1eu4D-yXr3RAAAVB_iOPc0218.png

-bash: ./testargs.sh: Argument list too long 咦…看來100有點承受不住,再來多幾次嘗試

wKioL1eu4ZWxV4UHAACS7ewXWgk076.png

314580可以,314595不行…有種曙光即現的感覺…

wKioL1eu5bfj1atqAACrilBIzaY610.png

大功告成j_0057.gif看來shell腳本最多支持314590個參數。




習題作業:

1、編寫腳本/root/bin/systeminfo.sh,顯示當前主機系統信息,包括主機名,IPv4地址,操作系統版本,內核版本,CPU型號,內存大小,硬盤大小。

#!/usr/bin/env bash
#
# Author: jacky18676887374@aliyun.com
# date: 20160811-22:58:36
# Vervion: 0.0.1
# Description:
# Synopsis:
#
#編寫腳本/root/bin/systeminfo.sh, 顯示當前主機系統信息,包括主機名,IPv4 地址,操作系統版本,內核版本,CPU 型號,內存大小,硬盤大小。
IPinfo=`ifconfig | grep 'inet\b'  | grep -v '127.0.0.1' | tr -s ' '  | cut -d' '  -f3`
CPUinfo=`lscpu | grep -i "model name:"`
Meninfo=`free -h | sed -n '2p' | tr -s ' ' | cut -d' ' -f2`
Diskinfo=`fdisk -l | sed -n '2p' | sed -r 's/.*[[:space:]]([0-9].*GB).*/\1/g'`
echo 'Hostname :'$(hostname)
echo 'Host IP:'${IPinfo}
echo 'OS version:'$(cat /etc/redhat-release)
echo 'Kernel version:'$(uname -r)
echo 'CPU '$CPUinfo
echo 'Memory :'$Meninfo
echo 'Harddisk:'$Diskinfo
unset IPinfo
unset CPUinfo
unset Meninfo
unset Diskinfo

1470985652723914.png

2、編寫腳本/root/bin/backup.sh,可實現每日將/etc/目錄備份到/root/etcYYYY-mm-dd中

#!/usr/bin/env bash
#
# Author: jacky18676887374@aliyun.com
# date: 20160811-23:42:05
# Vervion: 0.0.1
# Description:
# Synopsis:
#
#編寫腳本/root/bin/backup.sh,可實現每日將/etc/目錄備份到/root/etcYYYY-mm-dd中
backdir="/root/etc$(date +%F)"
cp -a /etc/. $backdir && echo " backup $backdir  finished."
unset backdir

1470985876490258.png

3、編寫腳本/root/bin/disk.sh,顯示當前硬盤分區中空間利用率最大的值

#!/usr/bin/env bash
#
# Author: jacky18676887374@aliyun.com
# date: 20160812-08:12:08
# Vervion: 0.0.1
# Description:
# Synopsis:
#
#編寫腳本/root/bin/disk.sh,顯示當前硬盤分區中空間利用率最大的值
#
maxdisk=`df | grep '/dev/sd' | tr -s ' ' | sort -nr -t' ' -k5 | head -1 | cut -d' ' -f1`
maxused=`df | grep '/dev/sd' | tr -s ' ' | sort -nr -t' ' -k5 | head -1 | cut -d' ' -f5`
echo '分區利用率最大值為:'$maxused
unset maxdisk
unset maxused

1470985977411200.png

4、編寫腳本/root/bin/links.sh,顯示正連接本主機的每個遠程主機的IPv4地址和連接數,并按連接數從大到小排序

#!/usr/bin/env bash
#
# Author: jacky18676887374@aliyun.com
# date: 20160812-08:27:18
# Vervion: 0.0.1
# Description:
# Synopsis:
#
#編寫腳本/root/bin/links.sh,顯示正連接本主機的每個遠程主機的IPv4地址和連接數,并按連接數從大到小排序。
echo -e "遠程主機連接統計為:\n\t連接數\t遠程主機IP"
netstat -nt | tr -s ' ' | cut -d' ' -f5 | tr -cs '0-9.' '\n' | egrep '([0-9]+.){3}[0-9]+' | sort | uniq -c | sort -nr | tr -s ' ' '\t'

1470986088490304.png

5、寫一個腳本/root/bin/sumid.sh,計算/etc/passwd文件中的第10個用戶和第20用戶的ID之和

#!/usr/bin/env bash
#
# Author: jacky18676887374@aliyun.com
# date: 20160812-14:00:37
# Vervion: 0.0.1
# Description:
# Synopsis:
#
#寫一個腳本/root/bin/sumid.sh,計算/etc/passwd文件中的第10個用戶和第20個用戶之和
UID1=`sed -n '10p' /etc/passwd | cut -d: -f3`
UID2=`sed -n '20p' /etc/passwd | cut -d: -f3`
let Sumid=$UID1+$UID2
echo -e "The 10 user ID is $UID1 ;\nthe 20 user ID is $UID2 ;\n\tthe sum of two users ID is $Sumid ."
unset UID1
unset UID2
unset Sumid

1470986400397747.png

6、寫一個腳本/root/bin/sumspace.sh,傳遞兩個文件路徑作為參數給腳本,計算這兩個文件中所有空白行之和

#!/usr/bin/env bash
#
# Author: jacky18676887374@aliyun.com
# date: 20160812-14:43:07
# Vervion: 0.0.1
# Description:
# Synopsis:
#
#寫一個腳本/root/bin/sumspace.sh,傳遞兩個文件路徑作為參數給腳本,計算這兩個文件中所有空白行之和
File1=`grep '^$' $1 | wc -l`
File2=`grep '^$' $2 | wc -l`
let Sumspace=$File1+$File2
echo "the sum of $1 and $2 spacelines is $Sumspace"
unset File1 
unset File2 
unset Sumspace

1470986609507552.png

7、寫一個腳本/root/bin/sumfile.sh,統計/etc, /var, /usr目錄中共有多少個一級子目錄和文件

#!/usr/bin/env bash
#
# Author: jacky18676887374@aliyun.com
# date: 20160812-14:52:14
# Vervion: 0.0.1
# Description:
# Synopsis:
#
#寫一個腳本/root/bin/sumfile.sh,統計/etc, /var, /usr目錄中共有多少個一級子目錄和文件
File1=/etc
File2=/var
File3=/usr
Count1=`ls -A $File1 | wc -l`
Count2=`ls -A $File2 | wc -l`
Count3=`ls -A $File3 | wc -l`
let Sumfile=${Count1}+${Count2}+${Count3}
echo -e "$File1 has $Count1 files;\n$File2 has $Count2 files;\n$File3 has $Count3 files;\n\tand total is  $Sumfile "
unset File1
unset File2
unset File3
unset Count1
unset Count2
unset Count3
unset Sumfile

1470987858158626.png

8、寫一個腳本/root/bin/argsnum.sh,接受一個文件路徑作為參數;如果參數個數小于1,則提示用戶“至少應該給一個參數”,并立即退出;如果參數個數不小于1,則顯示第一個參數所指向的文件中的空白行數

#!/usr/bin/env bash
#
# Author: jacky18676887374@aliyun.com
# date: 20160812-15:36:56
# Vervion: 0.0.1
# Description:
# Synopsis:
#
#寫一個腳本/root/bin/argsnum.sh,接受一個文件路徑作為參數;如果參數個數小于1,則提示用戶“至少應該給一個參數”,并立即退出;如果參數個數不小于1,則顯示第一個參數所指向的文件中的空白行數
[[ $# < 1 ]] && echo '至少應該給一個參數(文件)'  || (ArgSpace=`grep '^$' $1 | wc -l` ; echo "There is ${ArgSpace1} space lines in $1")
unset ArgSpace

1470988296753959.png

9、寫一個腳本/root/bin/hostping.sh,接受一個主機的IPv4地址做為參數,測試是否可連通。如果能ping通,則提示用戶“該IP地址可訪問”;如果不可ping通,則提示用戶“該IP地址不可訪問”

#!/usr/bin/env bash
#
# Author: jacky18676887374@aliyun.com
# date: 20160812-15:53:58
# Vervion: 0.0.1
# Description:
# Synopsis:
#
#寫一個腳本/root/bin/hostping.sh,接受一個主機的IPv4地址做為參數,測試是否可連通。如果能ping通,則提示用戶“該IP地址可訪問”;如果不可ping通,則提示用戶“該IP地址不可訪問”
ping -c 2 $1 &> /dev/null
[[ $? ==  0 ]] && echo '該IP地址可訪問'  || echo '該IP地址不可訪問'

1470988872262963.png

10、chmod -rw /tmp/file1,編寫腳本/root/bin/per.sh,判斷當前用戶對/tmp/fiile1文件是否不可讀且不可寫

#!/usr/bin/env bash
#
# Author: root
# date: 20160812-17:44:13
# Vervion: 0.0.1
# Description:
# Synopsis:
#
#chmod -rw /tmp/file1,編寫腳本/root/bin/per.sh,判斷當前用戶對/tmp/fiile1文件是否不可讀且不可寫
File=/tmp/file1
[ ! -r $File -a ! -w $File ] && echo '用戶對文件不可讀且不可寫' || echo '用戶對文件可讀或可寫,或可讀寫'
unset File

Image 20160812162305.png

11、編寫腳本/root/bin/nologin.sh和login.sh,實現禁止和充許普通用戶登錄系統。

cat nologin.sh 
#!/usr/bin/env bash
#
# Author: jacky18676887374@aliyun.com
# date: 20160812-17:51:10
# Vervion: 0.0.1
# Description:
# Synopsis:
#
#編寫腳本/root/bin/nologin.sh,實現禁止普通用戶登錄系統
#判斷/etc/nologin文件是否存在,如文件存在,則提示文件存在;如果不存在,則提示文件不存在,提示創建文件;無論文件是否存在都可以touch,完成后都輸出普通用戶無法登錄。
#
File=/etc/nologin
[ -f $File ] && echo "$File already exist." || echo -e "$File does not exist.\ncreating $File..."
touch /etc/nologin
echo "Linux ordinary users are not allowed to log on"

unset File

1470992214521829.png

#!/usr/bin/env bash
#
# Author: jacky18676887374@aliyun.com
# date: 20160812-17:51:10
# Vervion: 0.0.1
# Description:
# Synopsis:
#
#編寫腳本/root/bin/login.sh,實現允許普通用戶登錄系統
#判斷/etc/nologin文件是否存在,如文件不存在,提示文件不存在;如文件存在,則進行刪除文件,提示文件已刪除。完成后都輸出普通用戶允許登錄。
#
File=/etc/nologin
[ ! -f $File ] && echo -e "$File does not exist." || (rm -rf $File ; echo "$File deleted")
echo "Linux ordinary users are allowed to log on"
unset File

1470993408732069.png

12、寫一個腳本/root/bin/hostping.sh,接受一個主機的IPv4地址做為參數,先判斷是否合格IP,否,提示IP格式不合法并退出,是,測試是否可連通。如果能ping通,則提示用戶“該IP地址可訪問”;如果不可ping通,則提示用戶“該IP地址不可訪問”

cat hostping3.sh 
#!/usr/bin/env bash
#
# Author: jacky18676887374@aliyun.com
# date: 20160812-15:53:58
# Vervion: 0.0.1
# Description:
# Synopsis:
#
#寫一個腳本/root/bin/hostping.sh,接受一個主機的IPv4地址做為參數,先判斷是否合格IP,否,提示IP格式不合法并退出,是,測試是否可連通。如果能ping通,則提示用戶“該IP地址可訪問”;如果不可ping通,則提示用戶“該IP地址不可訪問”
echo $1 | egrep '\<([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){2}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\>' &>/dev/null
[[ $? -ne 0 ]] && echo "$1 is invalid" &&  exit
ping -c 3 -W 2  $1 &> /dev/null
[[ $? -eq  0 ]] && echo '該IP地址可訪問'  || echo '該IP地址不可訪問'

1470999117313086.png

13、計算1+2+3+…+100的值

[root@IP70-CentOS7 ~]# >>echo {1..100} | tr ' ' '+' | bc    #方法一
[root@IP70-CentOS7 ~]# >>echo $(seq 1 100) | tr ' ' '+' | bc    #方法二

1471000900679856.png

14、計算從腳本第一參數A開始,到第二個參數B的所有數字的總和,判斷B是否大于A,否提示錯誤并退出,是則計算之

#!/usr/bin/env bash
#
# Author: jacky18676887374@aliyun.com
# date: 20160813-18:57:05
# Vervion: 0.0.1
# Description:
# Synopsis:
#
#計算從腳本第一參數A開始,到第二個參數B的所有數字的總和,判斷B是否大于A,否提示錯誤并退出,是則計算之
#
[[ $1 -gt $2 ]] && echo "Error: $1 greater than $2" &&  exit
echo $(seq $1 $2) | tr ' ' '+' | bc

1471000425129395.png

原創文章,作者:昭其,如若轉載,請注明出處:http://www.www58058.com/34043

(0)
昭其昭其
上一篇 2016-08-15 09:25
下一篇 2016-08-15 09:25

相關推薦

  • bash特性、bash編程

    bash基礎特性: 命令行展開:~,{} 命令別名:alias,unalias 命令歷史:history 命令和路徑補全:$PATH glob通配符:*,?,[],[^], 快捷鍵:Ctrl+{a,e,l,c,u,k} 命令hash:   bash通配符及特殊符號: 通配符: ?:任意一個字符; *:匹配任意個任意字符; []:匹配括號內的任意一個…

    Linux干貨 2018-03-21
  • 基于kubernetes構建Docker集群管理詳解

    一、前言        Kubernetes 是Google開源的容器集群管理系統,基于Docker構建一個容器的調度服務,提供資源調度、均衡容災、服務注冊、動態擴縮容等功能套件,目前最新版本為0.6.2。本文介紹如何基于Centos7.0構建Kubernetes平臺,在正式介紹…

    2015-03-10
  • 網絡基礎知識

    網絡基礎知識: 網絡設備 TCP/IP協議 ARP協議 網絡設備:     HUB集線器: 工作在物理層,沒有學習能力,作用在于把各種節點匯聚在以它為中心的節點上,同時也有傳輸數據的作用,由于沒有學習能力,只能以廣播的形式將數據發送給與它相連的所有節點。 特點:共享帶寬,半雙工     &…

    Linux干貨 2016-09-02
  • 文件查找(Find和Locate)常用用法及摩根定律趣解(重要)

    文件查找(Find和Locate)常用用法及摩根定律趣解(重要) 摩根定律: 非(A 且 B)=(非 A)或(非 B) 非(A 或 B)=(非 A)且(非 B) 這樣看起來不是很好理解下面通過一些列圖片給大家展示; 圖(1)  圖(2)  圖二中的黑色就A且B,A且B的反面三種情況(如圖1)即為(非A)或(非B)。因此…

    Linux干貨 2016-08-21
  • 自制Linux系統實驗

    1、添加一塊新硬盤、并使系統識別 [root@centos6 ~]# echo "- – -" > /sys/class/scsi_host/host0/scan  [root@centos6 ~]# echo "…

    Linux干貨 2016-09-19
  • web服務介紹二)

    apache指令說明:http://httpd.apache.org/docs/2.2/mod/directives.html Listen 172.18.100.67:8081  監聽某個指定地址和端口啟動前檢查一下語法:    httpd -t 如果要監聽多個端口,要多行寫    Listen 80&nb…

    Linux干貨 2017-04-20

評論列表(1條)

  • 馬哥教育
    馬哥教育 2016-08-16 17:02

    有自己的思考與分析,通過自己的實踐來驗證自己的想法,很有思考性,再接再厲。

欧美性久久久久