Shell学习笔记

shell脚本学习

Posted by VK on September 14, 2019

Shell学习笔记

1. 多行注释:

:<<!   #相当于#if 0   //p.s.:这个多行注释符号不能有任何的缩进,放在句首才生效
echo "hahha"  
echo "comment"
!      #相当于#endif

2.获取命令行的值

disk_size=$(df / | awk '/\//{print $4}')  #其中awk里的两个斜杠/中间的内容为匹配行的内容
echo $disk_size

mem_size=$(free | awk '/Mem/{print $4}')
echo $mem_size

3.循环条件

disk_size=$(df / | awk '/\//{print $4}')  #其中awk里的两个斜杠/中间的内容为匹配行的内容
echo $disk_size
mem_size=$(free | awk '/Mem/{print $4}')
echo $mem_size

while [ $i -gt 0 ]
do 
if [ $disk_size -le 700000000 -a $mem_size -le 102400000 ] 
then
		mail -s "Warning" root <<EOF   #邮件到本地root,查看root邮件命令`mail -r root`
			 Insufficient resources,资源不足
EOF
fi
	let i--   #自增减其他数值: i+=n or i-=n
done 

4.EOF

Shell中通常将EOF与 « 结合使用,表示后续的输入作为子命令或子Shell的输入,直到遇到EOF为止,再返回到主调Shell。可以把EOF替换成其他东西,意思是把内容当作标准输入传给程序。

例子:自动登录mysql(root:root,passwd:123456),查询test库,test1表里的user=aa的记录。

#!/bin/sh
mysql -uroot -p123456 <<EOF
use test;
select * from testaa while a=10000; ###1000 not usr single quote mark,because a is int
# type,only char type need single quote mark.
exit
EOF

cat和EOF结合使用具有追加功能

使用Cat和EOF多行输入

cat >> /root/test.txt <<EOF 
abcdef 
hello word ! 
FFFFFFFFFFFFFFFFFFFFFFF 
EOF

以上的脚本命令是,在a.txt文件后面加上三行代码。

5.逻辑与或非

(1)与 “-a” : a是and
(2)或 “-o” : o是or
(3)非 “!” : !是not
i=6
b=3

while :
do
	if [ $b -lt 10 -o $i -gt 0 ]; then
		echo $b
		let i--
		let b+=2
	fi
	if [ !$i ]; then
		echo $i
	fi
	# !
	if [ ! -e /proc/mounts ]; then
    	mount -n -t proc /proc /proc
	fi
	# -z 字串为空/ -o or / -a and
    if[ -z "$HOSTNAME" -o "$HOSTNAME" = "(none)" ]; then
        HOSTNAME=localhost
    fi
    # -f 文件存在
    if[ -f /etc/sysconfig/network ]; then
        ./etc/sysconfig/network
    fi
    # -d 目录存在
    if [ ! -d /proc/bus/usb ]; then
        modprobe usbcore >/dev/null 2>&1
    else
        mount ...
    fi
done

6.文件比较运算符

1. -e filename 如果 filename存在,则为真 如: [ -e /var/log/syslog ] 
2. -d filename 如果 filename为目录,则为真 如: [ -d /tmp/mydir ] 
3. -f filename 如果 filename为常规文件,则为真 如: [ -f /usr/bin/grep ] 
4. -L filename 如果 filename为符号链接,则为真 如: [ -L /usr/bin/grep ] 
5. -r filename 如果 filename可读,则为真 如: [ -r /var/log/syslog ] 
6. -w filename 如果 filename可写,则为真 如: [ -w /var/mytmp.txt ] 
7. -x filename 如果 filename可执行,则为真 如: [ -L /usr/bin/grep ] 
8. filename1-nt filename2 如果 filename1比 filename2新,则为真 如: [/tmp/install/etc/services -nt /etc/services ] 
9. filename1-ot filename2 如果 filename1比 filename2旧,则为真 如: [ /boot/bzImage -ot arch/i386/boot/bzImage ]

7.字符串比较运算符(请注意引号的使用,这是防止空格扰乱代码的好方法)

1. -z string  如果 string长度为零,则为真 如:  [ -z "$myvar" ]
2. -n string  如果 string长度非零,则为真  如: [ -n "$myvar" ]
3. string1= string2  如果 string1与 string2相同,则为真 如:  ["$myvar" = "one two three"]
4. string1!= string2  如果 string1与 string2不同,则为真 如:  ["$myvar" != "one two three"]

8.算术比较运算符

 1. num1-eq num2  等于 如: [ 3 -eq $mynum ]
 2. num1-ne num2  不等于 如: [ 3 -ne $mynum ]
 3. num1-lt num2  小于 如: [ 3 -lt $mynum ]
 4. num1-le num2  小于或等于  如:[ 3 -le $mynum ]
 5. num1-gt num2  大于  如:[ 3 -gt $mynum ]
 6. num1-ge num2  大于或等于 如: [ 3 -ge $mynum ]

9.随机函数

num=$[RANDOM%100]
echo $num

while :
do
	read -p "input a num" guess
	if [ $guess -eq $num ]; then   #除了处需要then
		echo "congratulation"
		break
	elif [ $guess -gt $num ];then  #此处也需要then
		echo "bigger"
	else
		echo "smaller"
	fi
done

10. 用户判断(是否超级管理员)

#method1
echo $USER
if [ $USER == "root" ]; then  #字符比较用==,数值比较才使用 -eq等
	echo "right"
else
	echo "access denied"
fi

#method2 -- 使用 UID 数字对比版本
if [ $UID -eq 0 ];then
    yum ‐y install vsftpd
else
    echo "您不是管理员,没有权限安装软件"
fi

11.创建用户


#!/bin/bash
# 编写脚本:提示用户输入用户名和密码,脚本自动创建相应的账户及配置密码。如果用户
# 不输入账户名,则提示必须输入账户名并退出脚本;如果用户不输入密码,则统一使用默
# 认的 123456 作为默认密码。
 
read -p "请输入用户名: " user
#使用‐z 可以判断一个变量是否为空,如果为空,提示用户必须输入账户名,并退出脚本,退出码为 2
#没有输入用户名脚本退出后,使用$?查看的返回码为 2
if [ -z $user ];then
   	echo "您不需输入账户名"
 	exit 2
fi
#使用 stty ‐echo 关闭 shell 的回显功能
#使用 stty  echo 打开 shell 的回显功能
stty -echo
read -p "请输入密码: " pass
stty echo
pass=${pass:‐123456}   # ????这个语法什么意思?
useradd "$user"
echo "$pass" | passwd ‐‐stdin "$user"

12.取最大值

num1=3
num2=5

num=$[$num1>$num2?$num1:$num2]
echo $num

13.随机输出字符串内容

game=(石头 剪刀 布)
num=$[RANDOM%3]
computer=${game[$num]}
echo $computer

14. 编写脚本测试 192.168.4.0/24 整个网段中哪些主机处于开机状态,哪些主机处于关机状态

#!/bin/bash
# 编写脚本测试 192.168.4.0/24 整个网段中哪些主机处于开机状态,哪些主机处于关机
# 状态(for 版本)
for i in {1..254}
do
	# 每隔0.3秒ping一次,一共ping2次,并以1毫秒为单位设置ping的超时时间
   	ping ‐c 2 ‐i 0.3 ‐W 1 192.168.4.$i  &>/dev/null #&>需要连在一起,否则不会输出到/dev/null
    if  [ $? -eq 0 ];then
       	echo "192.168.4.$i is up"
   	else
       	echo  "192.168.4.$i is down"
   	fi
done
#---------------------------------------------------------------------------------
# 编写脚本测试 192.168.4.0/24 整个网段中哪些主机处于开机状态,哪些主机处于关机
# 状态(while 版本) 
i=1
while [ $i -le 254 ]
do
   	ping ‐c 2 ‐i 0.3 ‐W 1 192.168.4.$i  &>/dev/null
   	if  [ $? -eq 0 ];then
       	echo "192.168.4.$i is up"
    else
       	echo  "192.168.4.$i is down"
   	fi
   	let i++
done


# 状态(多进程版)
#定义一个函数,ping 某一台主机,并检测主机的存活状态
myping(){
ping ‐c 2 ‐i 0.3 ‐W 1 $1  &>/dev/null
if  [ $? -eq 0 ];then
	echo "$1 is up"
else
	echo "$1 is down"
fi
}
for i in {1..254}
do
   	myping 192.168.4.$i &
done
# 使用&符号,将执行的函数放入后台执行
# 这样做的好处是不需要等待ping第一台主机的回应,就可以继续并发ping第二台主机,依次类推。

15.显示进度条

jindu()
{
while :
do
	echo -n "#" 
	sleep 0.2
done
}

jindu2()
{
while :
do
	echo -n "?" 
	sleep 0.2
done
}

jindu &
jindu2 &
sleep 3
#cp -a $1 $2
killall $0 #当$0被kill掉时,所有在shell中运行的后台进程都会被terminated,如果注释掉这句,那么整个shell执行完毕后,该shell中开启的后台进程还会执行(如jindu和jindu2)
echo "copy done"

16.$参数的说明

$$ 
Shell本身的PID(ProcessID) 
$! 
Shell最后运行的后台Process的PID 
$? 
最后运行的命令的结束代码(返回值) 
$- 
使用Set命令设定的Flag一览 
$* 
所有参数列表。如"$*"用「"」括起来的情况、以"$1 $2$n"的形式输出所有参数。 
$@ 
所有参数列表。如"$@"用「"」括起来的情况、以"$1" "$2""$n" 的形式输出所有参数。 
$# 
添加到Shell的参数个数 
$0 
Shell本身的文件名 
$1$n 
添加到Shell的各参数值

P.S.:
$*$@ 都表示传递给函数或脚本的所有参数,不被双引号(" ")包含时,都以"$1" "$2""$n" 的形式输出所有参数。

但是当它们被双引号(" ")包含时,"$*" 会将所有的参数作为一个整体,以"$1 $2$n"的形式输出所有参数;"$@" 会将各个参数分开,以"$1" "$2""$n" 的形式输出所有参数。

#############################示例###############################
 1 #!/bin/bash
 2 #
 3 printf "The complete list is %s\n" "$$"
 4 printf "The complete list is %s\n" "$!"
 5 printf "The complete list is %s\n" "$?"
 6 printf "The complete list is %s\n" "$*"
 7 printf "The complete list is %s\n" "$@"
 8 printf "The complete list is %s\n" "$#"
 9 printf "The complete list is %s\n" "$0"
10 printf "The complete list is %s\n" "$1"
11 printf "The complete list is %s\n" "$2
结果:
[localhost ~]$ bash params.sh 123456 QQ
The complete list is 24249
The complete list is
The complete list is 0
The complete list is 123456 QQ
The complete list is 123456
The complete list is QQ
The complete list is 2
The complete list is params.sh
The complete list is 123456
The complete list is QQ

17.,动态时针版本;定义一个显示进度的函数,屏幕快速显示| / ‐ \


#!/bin/bash
# 进度条,动态时针版本
# 定义一个显示进度的函数,屏幕快速显示|  / ‐ \
rotate_line(){
INTERVAL=0.5  #设置间隔时间
COUNT="0"     #设置4个形状的编号,默认编号为 0(不代表任何图像)
while :
do
  COUNT=`expr $COUNT + 1` #执行循环,COUNT 每次循环加 1,(分别代表4种不同的形状)
  case $COUNT in          #判断 COUNT 的值,值不一样显示的形状就不一样
  "1")                    #值为 1 显示‐
          echo -e '‐'"\b\c"
          sleep $INTERVAL
          ;;
    "2")                  #值为 2 显示\\,第一个\是转义
          echo -e '\\'"\b\c"
          sleep $INTERVAL
          ;;
    "3")                  #值为 3 显示|
          echo -e "|\b\c"
          sleep $INTERVAL
          ;;
   "4")                   #值为 4 显示/
          echo -e "/\b\c"
          sleep $INTERVAL
          ;;
    *)                    #值为其他时,将 COUNT 重置为 0
          COUNT="0";;
    esac
done
}
rotate_line

18.乘法表

for i in `seq 9` #用于产生从某个数到另外一个数之间的所有整数,seq 1 10 结果是1 2 3 4 5 6 7 8 9 10
do
	for j in `seq $i`
	do
		echo -n "$i*$j=$[$i*$j] " #其中 $[$i*$j] 等效于 $[i*j]
	done
	echo -e " "
done

19.使用死循环实时显示 eth0 网卡发送的数据包流量

#!/bin/bash
# 使用死循环实时显示 eth0 网卡发送的数据包流量 
 
while :
do
 	echo  '本地网卡 eth0 流量信息如下: '
  	ifconfig eth0 | grep "RX pack" | awk '{print $5}'
    ifconfig eth0 | grep "TX pack" | awk '{print $5}'
   	sleep 1
done

20. 使用 user.txt 文件中的人员名单,在计算机中自动创建对应的账户并配置初始密码本脚本执行,需要提前准备一个 user.txt 文件,该文件中包含有若干用户名信息


#!/bin/bash
# 使用 user.txt 文件中的人员名单,在计算机中自动创建对应的账户并配置初始密码
# 本脚本执行,需要提前准备一个 user.txt 文件,该文件中包含有若干用户名信息
for i in `cat user.txt`
do
   	useradd  $i
   	echo "123456" | passwd ‐‐stdin $i
done

21.编写批量修改扩展名脚本

#!/bin/bash
# 编写批量修改扩展名脚本,如批量将 txt 文件修改为 doc 文件 
# 执行脚本时,需要给脚本添加位置参数
# 脚本名  txt  doc(可以将 txt 的扩展名修改为 doc)
# 脚本名  doc  jpg(可以将 doc 的扩展名修改为 jpg)
 
for i in "ls *.$1"
do
   	mv $i ${i%.*}.$2  ##The ${variable%.*} notation means take the value of $variable, strip off the pattern .* from the tail of the value
done

22.使用 expect 工具自动交互密码远程其他主机安装 httpd 软件

#!/bin/bash
# 使用 expect 工具自动交互密码远程其他主机安装 httpd 软件 
 
# 删除~/.ssh/known_hosts 后,ssh 远程任何主机都会询问是否确认要连接该主机
rm  ‐rf  ~/.ssh/known_hosts
expect <<EOF
spawn ssh 192.168.4.254
 
expect "yes/no" {send "yes\r"}
# 根据自己的实际情况将密码修改为真实的密码字串
expect "password" {send  "密码\r"}
expect "#" {send  "yum ‐y install httpd\r"}
expect "#" {send  "exit\r"}
EOF