Linux SHELL 脚本编程详解

Linux SHELL 脚本编程

  • 脚本编程详解
    • 名词解释
    • shell 脚本
    • 脚本中的条件测试
    • bash 测试分类
    • 脚本的状态返回值
    • 脚本语法检测和调试执行
    • 编程脚本之用户交互
  • 脚本执行方式
    • 1、选择执行
      • if 语句
      • case 语句
    • 2、循环执行
      • 2.1 for 循环
        • LIST 列表的生成方式
        • for 循环 示例
        • for 循环的特殊用法
      • 2.2 while 循环
      • 2.3 until 循环
  • 脚本示例
    • 1、vim 如何定制自动缩进四个字符。
    • 2、实现自动添加三个用户,并计算这三个用户的 uid 之和。
    • 3、通过命令传递两个文本文件路径给脚本,计算其空白行数之和。
    • 4、通过参数传递一个用户名给脚本,此用户不存时,则添加之。
    • 5、通过命令行参数给定两个数字,输出其中较大的数值。
    • 6、脚本参数传递一个文件路径给脚本,判断此文件的类型。
    • 7、传递一个参数给脚本,此参数为用户名;根据其ID号来判断用户类型。
    • 8、写一个脚本,要求如下:
    • 9、分别求100以内所有偶数之和,以及所有奇数之和。
    • 10、计算当前系统上的所有用的id之和。
    • 11、通过脚本参数传递一个目录给脚本,而后计算此目录下所有文本文件的行数之和;并说明此类文件的总数。
    • 12、计算/etc/passwd文件中的第10个用户和第20个用户的id号之和。
    • 13、计算/etc/rc.d/init.d/functions和/etc/inittab文件的空白行数之和。
    • 14、编写一个脚本,找出172.16.141.X网络中哪些主机地址被使用,哪些未被使用,并把结果保存至相应的文件中。
    • 15、写一个脚本,实现:能探测C类、B类或A类网络中的所有主机是否在线。
    • 16、编写脚本,通过命令行参数传入一个用户名,判断ID是偶数还是奇数。
    • 17、分别用while、for循环检测10.0.0.1/24网段存活的IP地址

脚本编程详解

编程语言的分类:根据运行方式
	1、编译运行:源代码 --> 编译器 (编译)--> 程序文件
	2、解释运行:源代码 --> 运行时启动解释器,由解释器边解释边运行
根据其编程过程中功能的实现是调用库还是调用外部的程序文件:
	1、shell脚本编程:利用系统上的命令及编程组件进行编程
	2、完整编程:利用库或编程组件进行编程
编程模型:过程式编程语言,面向对象的编程语言
程序=指令+数据
	1、过程式:以指令为中心来组织代码,数据是服务于代码;
		顺序执行
		选择执行
		循环执行
		代表:C,bash
	2、对象式:以数据为中心来组织代码,围绕数据来组织指令;
		类(class):实例化对象,method;
		代表:Java, C++, Python

名词解释

变量:
	1、局部变量
	2、本地变量
	3、环境变量
	4、位置参数变量
	5、特殊变量

具体参考:
https://blog.csdn.net/weixin_44983653/article/details/95232625
  • 位置参数变量
位置参数变量 :主要是向脚本传递参数。

# myscript.sh  argu1 argu2

引用方式:
	argu1 argu2
      $1,   $2, ..., ${10},  ${11}, ...
				
轮替:
	shift  [n]:位置参数轮替

示例:
root@LeeMumu:~# cat echo.sh           # 通过此脚本,了解位置参数变量
#!/bin/bash

echo $1
echo $2

root@LeeMumu:~# ./echo.sh "The line 1." "The line 2."
The line 1.
The line 2.
  • 特殊变量
$0:脚本文件路径本身
$#:脚本参数的个数
$*:所有参数
$@:所有参数
  • 算术运算和赋值
常用的算术运算符号:
	1、+   加
	2、-   减
	3、*   乘
	4、/   除
	5、**  次方
	6、%   余数
	
算术运算格式:
	1、let  VAR=算术运算表达式
	2、VAR=$[算术运算表达式]
	3、VAR=$((算术运算表达式))
		# 给变量空间赋值时一定要使用 $[ ] 或者 $(( ))
	4、VAR=$(expr $ARG1 $OP $ARG2)
		# (): 括号内部是运行命令,直接取命令运行结果

# 注意:乘法符号在有些场景中需要使用转义符。

增强型赋值:
	变量做某种算术运算后回存至此变量中,如下两种赋值方式表示同一个意思:
		let i=$i+#
		let i+=#
	常用的增强型赋值:		
		+=,-=,*=, /=, %=
	
	自增:
		VAR=$[$VAR+1]
		# 前面的 VAR 是变量空间,后面的 $VAR 是直接取变量空间里的值,注意区分
			let  VAR+=1
			let  VAR++
						
	自减:
		VAR=$[$VAR-1]
			let  VAR-=1
			let  VAR--
%(余数) 示例:
root@LeeMumu:~# yushu=$((9%2))
root@LeeMumu:~# echo $yushu
1
root@LeeMumu:~# yushu=$((8%2))
root@LeeMumu:~# echo $yushu
0

shell 脚本

1、什么是 shell 脚本?
	1、shell 脚本是过程式编程,解释运行,依赖于外部程序文件运行。
	2、shell 脚本是命令的堆积。
# 很多命令不具有幂等性,需要用程序逻辑来判断运行条件是否满足,以避免其运行中发生错误。

2、如何编写 shell 脚本?
	脚本文件的第一行,顶格位置需要给出:
		shebang,解释器路径,用于指明解释执行当前脚本的解释器程序文件。
	常见的解释器:
		#!/bin/bash
		#!/usr/bin/python
		#!/usr/bin/perl
	同时,在脚本顶部还可以加入版本、作者和描述等信息,如下:	
		#!/bin/bash
		# Version: 0.0.1
		# Author: LeeMumu
		# Description: XXX

3、如何运行 shell 脚本?
	(1) 赋予执行权限,并直接运行此程序文件
		chmod +x /PATH/TO/SCRIPT_FILE
		source /PATH/TO/SCRIPT_FILE
	(2) 直接运行解释器,将脚本以命令行参数传递给解释器程序
		bash /PATH/TO/SCRIPT_FILE

4、shell 脚本注意事项:
	(1) 脚本中的空白行会被解释器忽略
	(2) 脚本中,除了shebang,余下所有以#开头的行,都会被视作注释行而被忽略;此即为注释行
	(3) shell 脚本的运行是通过运行一个子shell进程实现的

脚本中的条件测试

条件测试:判断某需求是否满足,需要由测试机制来实现。
		
如何编写测试表达式以实现所需的测试:
	(1) 执行命令,并利用命令状态返回值来判断;
		0:成功
		1-255:失败
	(2) 测试表达式
		test  EXPRESSION
		[ EXPRESSION ]
		[[ EXPRESSION ]]
				
# 注意:EXPRESSION两端必须有空白字符,否则为语法错误。

bash 测试分类

bash 的测试类型:
	1、数值测试
	2、字符串测试
	3、文件测试
	4、组合条件测试
  • 1、数值测试
数值测试:数值比较
	-eq:是否等于     
		# [ $num1 -eq $num2 ],注意空格
	-ne:是否不等于
	-gt:是否大于
	-ge:是否大于等于
	-lt:是否小于
	-le:是否小于等于
示例:
root@LeeMumu:~# [ 2 -eq 2 ]            # 命令执行成功
root@LeeMumu:~# echo $?
0
root@LeeMumu:~# [ 2 -gt 2 ]            # 命令执行失败
root@LeeMumu:~# echo $?
1
  • 2、字符串测试
字符串测试:
	==:是否等于
		# [ STRING1 == STRING2 ],注意空格
	> :是否大于
	< :是否小于
	!=:是否不等于
	=~:左侧字符串是否能够被右侧的PATTERN所匹配
				
	-z "STRING":判断指定的字串是否为空;空则为真,不空则假
		# [[ -z “STRING” ]]
	-n "STRING":判断指定的字符串是否不空;不空则真,空则为假			
	# 注意:
		(1) 字符串要加引用
		(2) 要使用 [[ ]]				
示例:
root@LeeMumu:~# [ a == b ]             # 命令执行失败
root@LeeMumu:~# echo $?
1
root@LeeMumu:~# [ aba == baa ]         # 命令执行失败
root@LeeMumu:~# echo $?
1
root@LeeMumu:~# [ a == a ]             # 命令执行成功
root@LeeMumu:~# echo $?
0
root@LeeMumu:~# [[ -z "" ]]            # 命令执行成功,字符串为空则为真
root@LeeMumu:~# echo $?
0
root@LeeMumu:~# [[ -z "aaa" ]]         # 命令执行失败,字符串非空则为假
root@LeeMumu:~# echo $?
1
  • 3、文件测试
文件测试:
1、存在性测试
	-a  FILE
	-e  FILE
		文件的存在性测试,存在则为真,否则则为假

2、存在性及类型测试
	-b  FILE:是否存在并且为 块设备文件
	-c  FILE:是否存在并且为 字符设备文件
	-d  FILE:是否存在并且为 目录文件
	-f  FILE:是否存在并且为 普通文件
	-h  FILE:是否存在并且为 符号链接文件
	-L  FILE:是否存在并且为 符号链接文件
	-p  FILE:是否存在且为 命名管道文件
	-S  FILE:是否存在且为 套接字文件

3、文件权限测试:
	-r  FILE:是否存在并且 对当前用户可读
	-w  FILE:是否存在并且 对当前用户可写
	-x  FILE:是否存在并且 对当前用户可执行

4、特殊权限测试:
	-u  FILE:是否存在并且 拥有suid权限
	-g  FILE:是否存在并且 拥有sgid权限
	-k  FILE:是否存在并且 拥有sticky权限
				
5、文件是否有内容:
	-s  FILE:是否有内容,有内容为真,没内容为假
				
6、时间戳:
	-N  FILE:文件自从上一次读操作后是否被修改过
				
7、从属关系测试:
	-O  FILE:当前用户是否为文件的属主
	-G  FILE:当前用户是否属于文件的属组

8、双目测试:
	FILE1  -ef  FILE2:FILE1与FILE2是否指向同一个文件系统的相同inode的硬链接;
	FILE1  -nt  FILE2:FILE1是否新于FILE2,新为真,否则为假
	FILE1  -ot  FILE2:FILE1是否旧于FILE2,旧为真,否则为假					
示例:
root@LeeMumu:~# touch space.txt            # 创建空文件
root@LeeMumu:~# cat space.txt 
root@LeeMumu:~# [[ -s space.txt ]]         # 有内容为真,没内容为假
root@LeeMumu:~# echo $?
1
root@LeeMumu:~# echo 1 > space.txt 
root@LeeMumu:~# [[ -s space.txt ]]
root@LeeMumu:~# echo $?
0
root@LeeMumu:~# [[ -e space.backup.txt ]]   # 存在为真,不存在为假
root@LeeMumu:~# echo $?
1
root@LeeMumu:~# touch space.backup.txt
root@LeeMumu:~# [[ -e space.backup.txt ]]
root@LeeMumu:~# echo $?
0
  • 4、组合条件测试
逻辑运算:
第一种方式:
	1、与运算:COMMAND1 && COMMAND2
			# && 前面为真时, && 后面就继续执行
			# && 前面为假时, && 后面就不执行
	2、或运算:COMMAND1 || COMMAND2
			# 常用于判断此用户是否存在,如果不存在就对用户进行添加。
			# id user1 &> /dev/null || useradd user1
			# || 前面为真时, || 后面就不执行
			# || 前面为假时, || 后面就继续执行
	3、非运算:! COMMAND 
		
	例如:
		# [ -O FILE ] && [ -r FILE ]
						
第二种方式:
	1、与运算:EXPRESSION1  -a  EXPRESSION2
	2、或运算:EXPRESSION1  -o  EXPRESSION2
	3、非运算:! EXPRESSION
						
	例如:
		# [ -O FILE -a -x FILE ]
示例:
root@LeeMumu:~# [ 1 -eq 2 ] && echo 2
root@LeeMumu:~# [ 1 -lt 2 ] && echo 2
2
root@LeeMumu:~# [ 1 -eq 2 ] || echo 2
2
root@LeeMumu:~# [ 1 -lt 2 ] || echo 2

脚本的状态返回值

脚本的状态返回值:默认是脚本中执行的最后一条件命令的状态返回值。

可用如下命令自定义状态退出状态码
	# exit [n]:n为指定的状态码,一般制定为 1~255 结束脚本执行。

注意:shell进程遇到exit时,即会终止,因此,整个脚本执行即为结束。

脚本语法检测和调试执行

1、检测脚本中的语法错误:
	# bash -n /path/to/some_script
		
2、对脚本进行调试执行:
	# bash -x /path/to/some_script

编程脚本之用户交互

用户交互时,会使用到 read 命令。
该命令是从键盘读取变量的值,通常用在shell脚本中与用户进行交互的场合。该命令可以一次读取多个变量的值,变量和输入的值都需要使用空格隔开。

注意:在用户交互过程中,如果对输入的内容进行删除,需要同时使用 Ctrl + Delete 组合键。

read:从键盘读取变量值

使用格式:
read  [option]... [name ...]
	-p 'PROMPT'              # 指定读取值时的提示符
	-t TIMEOUT               # 指定读取值时等待的时间(秒)
示例:
root@LeeMumu:~# cat read.sh 
#!/bin/bash
#
read -p "Please input what you want:" aBa    # 输入的信息赋值给了变量 aBa
echo "You input the $aBa!"
root@LeeMumu:~# ./read.sh 
Please input what you want:This is a new line
You input the This is a new line!

脚本执行方式

shell 脚本是过程式编程语言,代码的执行顺序分为:

1、顺序执行
	# 逐条运行脚本代码
	
2、选择执行
	# 代码有一个分支:条件满足时才会执行
	# 两个或以上的分支:只会执行其中一个满足条件的分支
	
3、循环执行
	# 代码片断(循环体)要执行0、1或多个来回

1、选择执行

if 语句

单分支的if语句 格式:
if  测试条件
then
	代码分支
fi
双分支的if语句 格式:
if  测试条件; then
	条件为真时执行的分支
else
	条件为假时执行的分支
fi
多分支的if语句
if  CONDITION1; then
	条件1为真 分支
elif  CONDITION2; then
	条件2为真 分支
elif  CONDITION3; then
	条件3为真 分支
	... ...
elif  CONDITIONn; then
	条件n为真 分支
else
	所有条件均不满足时的分支
fi

注意:即便多个条件可能同时都能满足,分支只会执行中其中一个,首先测试为“真”的条件。

case 语句

语法格式:
case  $VARAIBLE  in  
PAT1)
	分支1
	;;
PAT2)
	分支2
	;;
	...
*)
	分支n
	;;
esac
对如上 case 语法格式进行说明:
	# case                 关键字
	# in                   关键字
	# PAT1)                仅支持 glob 风格的通配符号
	# VARDIBLE             变量
	# *)                  相当于 else
	# esac                 结束关键字(与 case 相反)
	# ;;                   双分号
	# 适用于变量值同多个字符串进行等值或不等值比较的情形,仅能替代部分多分支 if 语句
# case 支持 glob 风格的通配符
	*            # 任意长度的任意字符;
	?            # 任意单个字符;
    []           # 范围内任意单个字符;
	a|b          # a或b			

示例:写一个服务框架脚本。要求如下:

$lockfile,  值/var/lock/subsys/SCRIPT_NAME
				
(1) 此脚本可接受start, stop, restart, status四个参数之一;
(2) 如果参数非此四者,则提示使用帮助后退出;
(3) start,则创建lockfile,并显示启动;
	stop,则删除lockfile,并显示停止;
	restart,则先删除此文件再创建此文件,而后显示重启完成;
	status,如果lockfile存在,则显示running,否则,则显示为stopped。				
脚本如下:
#!/bin/bash
#
# chkconfig: - 50 50
# description: test service script
#
prog=$(basename $0)
lockfile=/var/lock/subsys/$prog

case $1  in
start)
	if [ -f $lockfile ]; then
		echo "$prog is running yet."
	else
		touch $lockfile
		[ $? -eq 0 ] && echo "start $prog finshed."
	fi
	;;
stop)
	if [ -f $lockfile ]; then
		rm -f $lockfile
		[ $? -eq 0 ] && echo "stop $prog finished."
	else
		echo "$prog is not running."
	fi
	;;
restart)
	if [ -f $lockfile ]; then
		rm -f $lockfile
		touch $lockfile
		echo "restart $prog finished."
	else
		touch -f $lockfile
		echo "start $prog finished."
	fi
	;;
status)
	if [ -f $lockfile ]; then
		echo "$prog is running"
	else
		echo "$prog is stopped."
	fi
	;;
*)
	echo "Usage: $prog {start|stop|restart|status}"
		exit 1
esac
命令执行:
# cp testservice /etc/init.d/
# chkconfig --add testservice
# chkconfig --list testservice
# service testservice start
# ls /var/lock/subsys/             # 启动服务后都会在这个目录下进行文件创建

2、循环执行

循环执行:是指将一段代码重复执行0、1或多次。
	进入条件:条件满足时才进入循环。
	退出条件:每个循环都应该有退出条件,以有机会退出循环。
循环分为三种:
	1、for循环
	2、while循环
	3、until循环
进入条件:
	for:列表元素非空
	while:条件测试结果为“真”
	unitl:条件测试结果为“假”
退出条件:
	for:列表元素遍历完成
	while:条件测试结果为“假”
	until:条件测试结果为“真”
循环控制语句:
# continue:提前结束本轮循环,不会执行后面的命令,直接进入下一轮循环判断。
while  CONDITION1; do
	CMD1
	...
	if  CONDITION2; then
		continue
	fi
	CMDn
	...
done

# break:提前跳出循环
while  CONDITION1; do
	CMD1
	...
	if  CONDITION2; then
		break
	fi
done
创建死循环:
while true; do
	循环体
done
退出方式:
	某个测试条件满足时,让循环体执行break命令。
示例:求100以内所有偶数之和;										
#!/bin/bash
#
declare -i evensum=0
declare -i i=0

while [ $i -le 100 ]; do
	let i++
	if [ $[$i%2] -eq 1 ]; then
		continue
	fi
	let evensum+=$i
done

echo "Even sum: $evensum"
示例:求100以内所奇数之和
#!/bin/bash
#
declare -i oddsum=0
declare -i i=1

while true; do
	let oddsum+=$i
	let i+=2
	if [ $i -gt 100 ]; then
		break
	fi
done

sleep 命令说明:

sleep 命令:
	- delay for a specified amount of time
	
命令格式:		
# sleep NUMBER

sleep 示例:每隔3秒钟到系统上获取已经登录用户的用户的信息;其中,如果logstash用户登录了系统,则记录于日志中,并退出。

#!/bin/bash
#
while true; do
	if who | grep "^logstash\>" &> /dev/null; then
		break
	fi
	sleep 3
done

echo "$(date +"%F %T") logstash logged on" >> /tmp/users.log	
				
#!/bin/bash
#
until who | grep "^logstash\>" &> /dev/null; do
	sleep 3
done

echo "$(date +"%F %T") logstash logged on" >> /tmp/users.log	

2.1 for 循环

for 循环包括以下两种
	1、遍历列表
	2、控制变量
遍历列表:

语法格式:
for  VARAIBLE  in  LIST; do
	循环体
done

参数解释:
1、for 是 关键字
2、VARAIBLE 是 变量 
3、in 是 关健字
4、LIST 是 赋值列表
5、do 和 done 是 关键字

VARAIBLE 赋值的三种形式:
	1、VARAIBLE = VALUE
	2、read 语句
	3、for 语句

进入和退出条件:
	1、进入条件:只要列表有元素,即可进入循环
	2、退出条件:列表中的元素遍历完成

LIST 列表的生成方式

一般有如下五种:

  • 1、直接给出
root@LeeMumu:~# echo 1 2 3 4 5 
1 2 3 4 5
  • 2、整数列表
(1)、{start..end}
root@LeeMumu:~# echo {1..5}
1 2 3 4 5

(2)、seq [start  [incremtal]]  last      # 中间参数是 步长
root@LeeMumu:~# seq 1 3
1
2
3
root@LeeMumu:~# seq 3
1
2
3
root@LeeMumu:~# seq 3 3 9
3
6
9
  • 3、返回列表参数
ls:返回列表 一行一个
cat:查看文件的返回列表参数

# 只要结果能输出字串的
  • 4、glob
匹配符合条件的列表:
# ls -d /etc/p*
  • 5、变量引用
$@ :参数传递
$* :参数传递
root@LeeMumu:~# passwd_Lines=`wc -l /etc/passwd | cut -d' ' -f1`  
	# 注意:以上命令是 反引号,作命令引用
root@LeeMumu:~# echo $passwd_Lines
33
root@LeeMumu:~# seq 1 $passwd_Lines
1
2
...
32
33
root@LeeMumu:~#  echo {1.."$passwd_Lines"}
{1..33}
	# 注意:使用花括号时引用变量时,不会生效,可用 seq
root@LeeMumu:~# echo {1..$passwd_Lines}
{1..33}
root@LeeMumu:~# echo {1..33}
1 2 3 4 5 6 ... ...  32 33
root@LeeMumu:~# echo '$passwd_Lines'
$passwd_Lines

for 循环 示例

1、求 100 以内的正整数之和。

#!/bin/bash
#
declare -i sum=0

for i in {1..100}; do
	echo "\$sum is $sum, \$i is $i"
	sum=$[$sum+$i]
done

echo $sum

2、判断/var/log目录下的每一个文件的内容类型。

#!/bin/bash
#
for filename in /var/log/*; do
	if [ -f $filename ]; then
		echo "Common file."
	elif [ -d $filename ]; then
		echo "Directory."
	elif [ -L $filename ]; then
		echo "Symbolic link."
	elif [ -b $filename ]; then
		echo "block special file."
	elif [ -c $filename ]; then
		echo "character special file."
	elif [ -S $filename ]; then
		echo "Socket file."
	else
		echo "Unkown."
	fi					
done				

3、打印 九九乘法表

#外循环控制乘数,内循环控制被乘数;
#!/bin/bash
#
for j in {1..9}; do
	for i in $(seq 1 $j); do
		echo -n -e "${i}X${j}=$[${i}*${j}]\t"
	done
	echo 
done

for 循环的特殊用法

语法格式;
for  ((控制变量初始化;条件判断表达式;控制变量的修正语句)); do
	循环体
done

控制变量初始化:仅在循环代码开始运行时执行一次
控制变量的修正语句:每轮循环结束会先进行控制变量修正运算,而后再做条件判断
示例:求100以内所有正整数之和
#!/bin/bash
#
declare -i sum=0

for ((i=1;i<=100;i++)); do
	let sum+=$i
done

echo "Sum: $sum."

				
示例:打印九九乘法表
#!/bin/bash
#
for ((j=1;j<=9;j++)); do
	for ((i=1;i<=j;i++)); do
		echo -e -n "${i}X${j}=$[${i}*${j}]\t"
	done
	echo
done

2.2 while 循环

语法格式:
while  CONDITION; do
	循环体
	循环控制变量修正表达式
done

进入条件:CONDITION测试为 真
退出条件:CONDITION测试为 假	
示例:求100以内的正整数之和
#!/bin/bash
#
declare -i sum=0
declare -i i=1

while [ $i -le 100 ]; do
	let sum+=$i
	let i++
done

echo $sum
  • while 循环的特殊用法(遍历文件的行):
while  read  VARIABLE; do
	循环体;
done  <  /PATH/FROM/SOMEFILE

# 依次读取/PATH/FROM/SOMEFILE文件中的每一行,且将基赋值给VARIABLE变量
示例:找出ID号为偶数的用户,显示其用户名、ID及默认shell
#!/bin/bash
#
while read line; do
	userid=$(echo $line | cut -d: -f3)
	username=$(echo $line | cut -d: -f1)
	usershell=$(echo $line | cut -d: -f7)

	if [ $[$userid%2] -eq 0 ]; then
		echo "$username, $userid, $usershell."
	fi
done < /etc/passwd	

2.3 until 循环

until  CONDITION; do
	循环体
	循环控制变量修正表达式
done
		
进入条件:CONDITION测试为 假
退出条件:CONDITION测试为 真		
示例:求100以内的正整数之和
#!/bin/bash
#
declare -i sum=0
declare -i i=1

until [ $i -gt 100 ]; do
	let sum+=$i
	let i++
done

echo $sum

脚本示例

1、vim 如何定制自动缩进四个字符。

vim 的配置文件是:/etc/vimrc 
可以对此配置文件进行编辑,添加配置: set tabstop=4 ,重读配置,使文件生效即可。

如下:
[root@LeeMumu ~]# vi /etc/vimrc        # 编辑 vim 的配置文件
set tabstop=4
[root@LeeMumu ~]# source /etc/vimrc    # 重读配置文件。使文件生效

2、实现自动添加三个用户,并计算这三个用户的 uid 之和。

[root@LeeMumu ~]# ./sUMID.sh
Add user user21 successfully.
The user user21 ID is:1004. 
Add user user22 successfully.
The user user22 ID is:1005. 
Add user user33 successfully.
The user user33 ID is:1006. 
The sum of these UserID is:3015.
[root@LeeMumu ~]# tail -n 3 /etc/passwd
user21:x:1004:1017::/home/user21:/bin/bash
user22:x:1005:1018::/home/user22:/bin/bash
user33:x:1006:1019::/home/user33:/bin/bash
[root@LeeMumu ~]# cat sUMID.sh 
#!/bin/bash
#
declare -i sum=0

for i in user21 user22 user33; do
	if id $i &> /dev/null ; then
		echo "The user $i exists."
	else
		useradd $i
		echo "Add user $i successfully."
	fi
	ID=`grep "^$i" /etc/passwd | cut -d":" -f3`
#   ID=$(grep "^$i" /etc/passwd | cut -d":" -f3)           # 用 $() 或 `` 都可以
	echo "The user $i ID is:$ID. "
	sum=$[$sum+$ID]
done

	echo "The sum of these UserID is:$sum."

3、通过命令传递两个文本文件路径给脚本,计算其空白行数之和。

#!/bin/bash
#
file1_lines=$(grep "^$" $1 | wc -l)
file2_lines=$(grep "^$" $2 | wc -l)

echo "Total blank lines: $[$file1_lines+$file2_lines]"	

4、通过参数传递一个用户名给脚本,此用户不存时,则添加之。

第一种:
#!/bin/bash
#
if ! grep "^$1\>" /etc/passwd &> /dev/null; then
	useradd $1
	echo $1 | passwd --stdin $1 &> /dev/null
	echo "Add user $1 finished."
fi	

第二种:			
#!/bin/bash
#
if [ $# -lt 1 ]; then
	echo "At least one username."
	exit 2
fi

if ! grep "^$1\>" /etc/passwd &> /dev/null; then
	useradd $1
	echo $1 | passwd --stdin $1 &> /dev/null
	echo "Add user $1 finished."
fi		

第三种:			
#!/bin/bash
#
if [ $# -lt 1 ]; then
	echo "At least one username."
	exit 2
fi

if grep "^$1\>" /etc/passwd &> /dev/null; then
	echo "User $1 exists."
else
	useradd $1
	echo $1 | passwd --stdin $1 &> /dev/null
	echo "Add user $1 finished."
fi			

5、通过命令行参数给定两个数字,输出其中较大的数值。

第一种:
#!/bin/bash
#
if [ $# -lt 2 ]; then
	echo "Two integers."
	exit 2
fi

if [ $1 -ge $2 ]; then
	echo "Max number: $1."
else
	echo "Max number: $2."
fi

第二种:(相对于第一种来说,第二种是代码优化)
#!/bin/bash
#
if [ $# -lt 2 ]; then
	echo "Two integers."
	exit 2
fi

declare -i max=$1

if [ $1 -lt $2 ]; then
	max=$2
fi

echo "Max number: $max."

第三种:(if 语句可嵌套)
#!/bin/bash
#
if [ $# -lt 2 ]; then
	echo "TWO INTEGERS!"
	exit 1
else
	if [ $1 -lt $2 ]; then
		echo "The $2 is bigger than $1."
	elif [ $1 -eq $2 ]; then
		echo "The $1 is equal than $1."
	else
		echo "The $1 is bigger than $1."
	fi
fi 

6、脚本参数传递一个文件路径给脚本,判断此文件的类型。

#!/bin/bash
#
if [ $# -lt 1 ]; then
	echo "At least on path."
	exit 1
fi

if ! [ -e $1 ]; then
	echo "No such file."
	exit 2
fi

if [ -f $1 ]; then
	echo "Common file."
elif [ -d $1 ]; then
	echo "Directory."
elif [ -L $1 ]; then
	echo "Symbolic link."
elif [ -b $1 ]; then
	echo "block special file."
elif [ -c $1 ]; then
	echo "character special file."
elif [ -S $1 ]; then
	echo "Socket file."
else
	echo "Unkown."
fi	

7、传递一个参数给脚本,此参数为用户名;根据其ID号来判断用户类型。

(0: 管理员;1-999:系统用户;1000+:登录用户)

#!/bin/bash
#
[ $# -lt 1 ] && echo "At least on user name." && exit 1

! id $1 &> /dev/null && echo "No such user." && exit 2

userid=$(id -u $1)

if [ $userid -eq 0 ]; then
	echo "root"
elif [ $userid -ge 1000 ]; then
	echo "login user."
else
	echo "System user."
fi	

8、写一个脚本,要求如下:

(1) 列出如下菜单给用户:
disk) show disks info;
mem) show memory info;
cpu) show cpu info;
*) quit;
(2) 提示用户给出自己的选择,而后显示对应其选择的相应系统信息。
#!/bin/bash
#
cat << EOF
cpu) display cpu information
mem) display memory infomation
disk) display disks information
quit) quit
===============================
EOF

read -p "Enter your option: " option

while [ "$option" != "cpu" -a "$option" != "mem" -a "$option" != "disk" -a "$option" != "quit" ]; do
	echo "cpu, mem, disk, quit"
	read -p "Enter your option again: " option
done

if [ "$option" == "cpu" ]; then
	lscpu
elif [ "$option" == "mem" ]; then
	free -m
elif [ "$option" == "disk" ]; then
	fdisk -l /dev/[hs]d[a-z]
else
	echo "quit"
	exit 0
fi

9、分别求100以内所有偶数之和,以及所有奇数之和。

第一个脚本:
#!/bin/bash
#计算100以内所有奇数的和以及所有偶数的和;分别显示之
#奇数和变量
let SUM1=0
#偶数和变量
let SUM2=0
for I in {1..100}; do
	if [ $[$I%2] -eq 0 ]; then
		SUM1=$[$SUM1+$I]
	else
		SUM2=$[$SUM2+$I]
	fi
done

echo -e "SUM1=$SUM1\nSUM2=$SUM2"

第二个脚本:
#!/bin/bash
#
declare -i even=0
declare -i odd=0

for i in {1..100}; do
	if [ $[$i%2] -eq 0 ]; then
		even=$[$even+$i]
	else
		odd=$[$odd+$i]
	fi
done

echo "The sum of the even_number between 1 and 100 is: $even"
echo "The sum of the odd_number between 1 and 100 is: $odd"
echo "The sum of the integer between 1 and 100 is: $[$even+$odd]"

10、计算当前系统上的所有用的id之和。

#!/bin/bash
#

declare -i passwd_Lines=`wc -l /etc/passwd | cut -d' ' -f1`
declare -i sum_UID=0

for i in `cat /etc/passwd | cut -d':' -f3`; do
	sum_UID=$[$sum_UID+$i]
done

echo "The sum of the user-ID is:$sum_UID"

11、通过脚本参数传递一个目录给脚本,而后计算此目录下所有文本文件的行数之和;并说明此类文件的总数。

#!/bin/bash
#

declare -i count=0
declare -i line_count=0

if [ $# -eq 1 ];then
	if [ -d $1 ]; then
		for filename in $1* ;do
			if [ -f $filename ];then
				line_count=$[$line_count+`wc -l $filename | cut -d' ' -f1`]
				count=$[$count+1]
				echo "The Common_File $filename has $line_count lines."
			else
				exit 1
			fi
		done
	else 
		echo -e "Please Input Correct Directory.\nFor Example: /path/path/"
		exit 2
	fi
else
	echo "Please Input One Directory!"
	exit 3
	fi
echo " "
echo "The Number of Common_File is:$count"
echo "The Total Lines of Common_File is:$line_count"

12、计算/etc/passwd文件中的第10个用户和第20个用户的id号之和。

[root@LeeMumu ~]# bash sum1020.sh 
The UID OF the tenth user is: 11.
The UID OF the twentith user is: 59.
The UID_SUM OF the tenth user and the twentith user is: 70.
[root@LeeMumu ~]# cat sum1020.sh
#!/bin/bash
#
ID10=$(head -10 /etc/passwd | tail -1 | cut -d":" -f3)
ID20=$(head -20 /etc/passwd | tail -1 | cut -d":" -f3)

sum1020=$[$ID10+$ID20]

echo "The UID OF the tenth user is: $ID10."
echo "The UID OF the twentith user is: $ID20."
echo "The UID_SUM OF the tenth user and the twentith user is: $sum1020."

13、计算/etc/rc.d/init.d/functions和/etc/inittab文件的空白行数之和。

[root@LeeMumu ~]# bash sumSPACElines.sh 
The /etc/rc.d/init.d/functions has 91 space-lines.
The /etc/inittab has 0 space-lines.
The /etc/rc.d/init.d/functions and /etc/inittab totally have 91 space-lines.
[root@LeeMumu ~]# cat sumSPACElines.sh
#!/bin/bash
#
ID10=$(grep "^[[:space:]]*$"   /etc/rc.d/init.d/functions | wc -l)
ID20=$(grep "^[[:space:]]*$"   /etc/inittab | wc -l)

sum1020=$[$ID10+$ID20]

echo "The /etc/rc.d/init.d/functions has $ID10 space-lines."
echo "The /etc/inittab has $ID20 space-lines."
echo "The /etc/rc.d/init.d/functions and /etc/inittab totally have $sum1020 space-lines."

14、编写一个脚本,找出172.16.141.X网络中哪些主机地址被使用,哪些未被使用,并把结果保存至相应的文件中。

[root@LEEMUMU ~]# cat ping.sh 
#!/bin/bash
#

declare -i upnum=0
declare -i downnum=0
declare -i i=1

pinghost() {
	if ping $1 -c 1 -W 1 &>/dev/null; then
		echo -e "\033[1;32m$1 is up.\033[0m"  | tee -a up20190717.txt
		upnum=$[$upnum+1]
	else
		echo -e "\033[1;31m$1 is down.\033[0m"  | tee -a down20190717.txt
		downnum=$[$downnum+1]
	fi
	
}

while [ $i -le 254 ]; do
	pinghost 172.16.141.$i
	let i++
done

echo "Uphost is $upnum."
echo "Downhost is $downnum."

15、写一个脚本,实现:能探测C类、B类或A类网络中的所有主机是否在线。

#!/bin/bash
#

cping() {
local i=1
while [ $i -le 5 ]; do
	if ping -W 1 -c 1 $1.$i &> /dev/null; then
		echo "$1.$i is up"
	else
		echo "$1.$i is down."
	fi
	let i++
done
}

bping() {
local j=0
while [ $j -le 5 ]; do
	cping $1.$j
	let j++
done
}

aping() {
local x=0
while [ $x -le 255 ]; do
	bping $1.$x
	let x++
done
}

16、编写脚本,通过命令行参数传入一个用户名,判断ID是偶数还是奇数。

[root@LeeMumu ~]# ./evenorodd.sh 
Please Input One UserName:JC9
The UserID Of JC9 is even!
[root@LeeMumu ~]# ./evenorodd.sh
Please Input One UserName:jc8
The jc8 Not Exist!
Please Input Another UserName!
[root@LeeMumu ~]# ./evenorodd.sh
Please Input One UserName:JC6
The UserID Of JC6 is odd!
[root@LeeMumu ~]# cat evenorodd.sh 
#!/bin/bash
#
read -p "Please Input One UserName:" UserName

if ! id $UserName &> /dev/null; then
	echo -e "\e[1;31mThe $UserName Not Exist!\e[0m"
	echo -e "\e[1;32mPlease Input Another UserName!\e[0m"
	exit 1
else
	if [ $[`id -u $UserName`%2] -eq 0 ];then
		echo -e "\e[1;33mThe UserID Of $UserName is even!\e[0m"
	else	
		echo -e "\e[1;34mThe UserID Of $UserName is odd!\e[0m"
	fi
fi

17、分别用while、for循环检测10.0.0.1/24网段存活的IP地址

第一种:

#!/bin/bash
# 先定义函数,再引用函数
while_ping(){
    local i=1
    while [ $i -le 255 ];do
    ping -W 1 -c 1 $1.$i &> /dev/null
        if [ $? == 0 ];then
            echo "$1.$i is up"
        else
            echo "$1.$i is down"
        fi
        let i++
    done
}

########################################################

for_ping(){

    for i in {1..255};do
    ping -W 1 -c 1 $1.$i &> /dev/null
        if [ $? == 0 ];then
            echo "$1.$i is up"
        else
            echo "$1.$i is down"
        fi
    done
}

########################################################

if [ $# -lt 2 ];then
    echo "Usage sh $0 {for_ping|while_ping} Network"
    echo "Such as :for_ping 192.168.1 OR while_ping 192.168.1"
    exit 1
elif [[ $1 == "for_ping" ]];then
    echo "for_ping"
    for_ping $2
elif [[ $1 == "while_ping" ]];then
    echo "while_ping"
    while_ping $2
fi

第二种:

#!/bin/bash
for ip in {1..255};do
	ping -c 1 10.0.0.$ip > /dev/null 2>&1
	if [ $? -eq 0 ]; then
		echo 10.0.0.$ip is UP
	else
		echo 10.0.0.$ip is DOWN
	fi
done

##############################################

declare -i ip=1
while [ $ip -le 255 ]; do
    ping -c 1 10.0.0.$ip > /dev/null 2>&1
    if [ $? -eq 0 ]; then
        echo 10.0.0.$ip UP
    else
        echo 10.0.0.$ip DOWN
    fi
    let ip++
done

你可能感兴趣的:(Linux学习笔记)