今天我們來探討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個參數,運行之:
由實例我們可以得出初步結論:
-
0: shell腳本的名字;
-
N:N是1開始的正整數,shell腳本的第N個位置參數,當N是個位數數字,可以表示為$N;當N非個位數時候,需要 { } ,即${N} ;
-
#:shell腳本的參數的個數,以十進制計數;
-
*:參數列表
-
@:參數列表
對于前面的三個很好理解,但是*和@都是參數列表,難道說*=@嗎?第一反應就是:這不可能,一定是個坑。
到網上查找資料,在Chet Ramey , Brian Fox 著 邵加超(Jerry Fleming)譯注的《BASH中文文檔》看到說明介紹:
真對不起我的語文老師,幾遍下來,依然覺得很生澀,似懂非懂。只能動手結合實例理解:
#!/usr/bin/env bash # #測試腳本的位置參數: @ 和 * # echo 'This is $@ :>>>|'$@ echo 'This is $* :>>>|'$*
貌似看不出來個所以然,恍然想起echo命令是以行顯示內容,列表都變成一行輸出了。
思路:把參數列表傳遞給for循環的i變量,然后打印$i,
#!/usr/bin/env bash # #測試腳本的位置參數: @ 和 * # echo 'begin testing $@......' for i in $@ do echo $i done echo 'begin testing $*......' for i in $* do echo $i done
什么情況…還是一樣的,難道我的理解錯了?再來:
#!/usr/bin/env bash # #測試腳本的位置參數: @ 和 * # echo 'begin testing $@......' for i in "$@" do echo $i done echo 'begin testing $*......' for i in "$*" do echo $i done
真相浮出水面(我果然對不起語文老師)…再看一眼正確演示的腳本↓↓↓↓
由此可以得出最后結論:
-
0: shell腳本的名字;
-
N:N是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命令展開
-bash: ./testargs.sh: Argument list too long 咦…看來100有點承受不住,再來多幾次嘗試
314580可以,314595不行…有種曙光即現的感覺…
習題作業:
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
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
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
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'
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
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
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
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
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地址不可訪問'
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
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
#!/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
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地址不可訪問'
13、計算1+2+3+…+100的值
[root@IP70-CentOS7 ~]# >>echo {1..100} | tr ' ' '+' | bc #方法一 [root@IP70-CentOS7 ~]# >>echo $(seq 1 100) | tr ' ' '+' | bc #方法二
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
原創文章,作者:昭其,如若轉載,請注明出處:http://www.www58058.com/34043
有自己的思考與分析,通過自己的實踐來驗證自己的想法,很有思考性,再接再厲。