今天我们来探讨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.178linux.com/34043
评论列表(1条)
有自己的思考与分析,通过自己的实践来验证自己的想法,很有思考性,再接再厉。