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