在一些复杂的Linux维护工作中,大量重复性的输入和交互操作不但费时费力,而且容易出错。
而编写一个恰到好处的shell脚本程序,可以批量处理,自动化的完成一系列维护任务,大大减轻管理员的负担。
shell是一个命令解释器,它在操作系统的最外层,负责直接与用户进行对话,把用户的输入解释给操作系统,并处理各种各样的操作系统的输出结果,输出到屏幕反馈给用户。这种对话方式可是交互也可以是非交互式的,我们所输入的命令计算机是不识别的,这时就需要一种程序来帮助我们进行翻译,变成计算机能识别的二进制程序,同时又把计算机生成的结果返回给我们。
常见的shell_解释器程序有很多种,使用不同的 Shell时,共内部指令、命令行提示符等力而会存在一些区别。通过 /etc/shells 文件可以了解当前系统所支持的shell脚本种类
[root@c7-1 ~]# cat /etc/shells /bin/sh //是bash命令的软链接(己经被/bin/baah所替换) /bin/bash //基准于GNU的框菜下发E出的Shell /sbin/nologin #nologin:奇怪的shell,这个shell可以让用户无法登录主机。bash ( /bin/bash)是目前大多数Linux版本采用的默认shell。 /usr/bin/sh //已经被bash所替换 /usr/bin/bash //centos和redhat系统默认使用bash shell /bin/tcsh //csh的增强版,与csh完全兼容整合了csh,提供更多的功能。 /bin/csh //已经被/bin/bash 所替换(整合C shell,提供更多的功能) [root@c7-1 ~]#
这是因为系统某些服务在运行过程中,会去检查用户能够使用的shells,而这些shell的查询就是借由 /etc/shells 这个文件
当我登录的时候,系统就会给我shell让我来工作,而这个登录取得的shell就记录在 /etc/passwd 这个文件内。
不同的shell具备不同的功能,shell还决定了Linux中 默认的shell是/bin/bash,流行的shell有ash、bash、ksh、csh、zsh等,不同的shell都有自己的特点以及用途
目前大多数linux系统默认使用的是 bash shell,默认登陆shell是/bin/bash,可以查看 /etc/passwd 文件里注明
这个shell是针对用户而言的,可以查看/etc/passwd里面的 最后的字段使用的是哪个shell,如果想要修改可以用 chnod -s或者chsh-s来重新指定
shell脚本就是说我们把原来 linux 命令或语句放在一个文件中,然后通过这个程序文件去执行时,我们就说这个程序为 shell脚本或shell程序;我们可以在脚本中输入一系统的命令以及相关的语法语句组合,比如变量,流程控制语句等,把他们有机结合起来就形成了一个功能强大的shell 脚本
在需要完成大量复杂、重复性的工作时,不需要在命令行重复执行命令,直接运行shell脚本即可,大大的节省了时间提高了效率
#!/bin/bash #第一行为"#!/bin/bash",脚本中明(默认解释器)﹔表示此行以下的代码语句是通过/bin/bash程序来执行。 还有其他类型的解释器: #!/ysr/bin/bash #!/usr/bin/expect 注释信息:以"#"开头的语句表示为注释信息,被注释的语句在脚本运行时不会被执行
[root@c7-1 home]# vim test.sh #!/bin/bash cd /boot //切换到boot目录 pwd //查看当前目录 ls -lh vml* //查看所有vml(内核)文件
[root@c7-1 home]# ./test.sh -bash: ./test.sh: 权限不够 [root@c7-1 /]# /home/test.sh -bash: /home/test.sh: 权限不够 [root@c7-1 home]# ls -lh -rw-r--r--. 1 root root 38 9月 2 18:56 test.sh #若不给test.sh文件权限则不能执行 [root@c7-1 /]# chmod +x /home/test.sh //给test.sh可执行文件权限 [root@c7-1 home]# ls -lh -rwxr-xr-x. 1 root root 38 9月 2 18:56 test.sh [root@c7-1 home]# ./test.sh /boot -rwxr-xr-x. 1 root root 5.7M 7月 22 01:24 vmlinuz-0-rescue-88592b0b2e2b49fab4e71eedc23b1998 -rwxr-xr-x. 1 root root 5.7M 8月 23 2017 vmlinuz-3.10.0-693.el7.x86_64 [root@c7-1 /]# /home/test.sh /boot -rwxr-xr-x. 1 root root 5.7M 7月 22 01:24 vmlinuz-0-rescue-88592b0b2e2b49fab4e71eedc23b1998 -rwxr-xr-x. 1 root root 5.7M 8月 23 2017 vmlinuz-3.10.0-693.el7.x86_64 #给完权限之后,才能执行
[root@c7-1 home]# ls -lh -rw-r--r--. 1 root root 38 9月 2 18:56 test.s [root@c7-1 home]# bash test.sh /boot -rwxr-xr-x. 1 root root 5.7M 7月 22 01:24 vmlinuz-0-rescue-88592b0b2e2b49fab4e71eedc23b1998 -rwxr-xr-x. 1 root root 5.7M 8月 23 2017 vmlinuz-3.10.0-693.el7.x86_64 [root@c7-1 home]# sh test.sh /boot -rwxr-xr-x. 1 root root 5.7M 7月 22 01:24 vmlinuz-0-rescue-88592b0b2e2b49fab4e71eedc23b1998 -rwxr-xr-x. 1 root root 5.7M 8月 23 2017 vmlinuz-3.10.0-693.el7.x86_64
[root@c7-1 home]# source test.sh /boot -rwxr-xr-x. 1 root root 5.7M 7月 22 01:24 vmlinuz-0-rescue-88592b0b2e2b49fab4e71eedc23b1998 -rwxr-xr-x. 1 root root 5.7M 8月 23 2017 vmlinuz-3.10.0-693.el7.x86_64
[root@c7-1 /]# sh < /home/test.sh /boot -rwxr-xr-x. 1 root root 5.7M 7月 22 01:24 vmlinuz-0-rescue-88592b0b2e2b49fab4e71eedc23b1998 -rwxr-xr-x. 1 root root 5.7M 8月 23 2017 vmlinuz-3.10.0-693.el7.x86_64 [root@c7-1 /]# cat /home/test.sh | sh /boot -rwxr-xr-x. 1 root root 5.7M 7月 22 01:24 vmlinuz-0-rescue-88592b0b2e2b49fab4e71eedc23b1998 -rwxr-xr-x. 1 root root 5.7M 8月 23 2017 vmlinuz-3.10.0-693.el7.x86_64 [root@c7-1 /]# cat /home/test.sh | bash /boot -rwxr-xr-x. 1 root root 5.7M 7月 22 01:24 vmlinuz-0-rescue-88592b0b2e2b49fab4e71eedc23b1998 -rwxr-xr-x. 1 root root 5.7M 8月 23 2017 vmlinuz-3.10.0-693.el7.x86_64
[root@c7-1 /]# vim /home/test.sh #!/bin/bash #hellow cd /boot echo "当前目录位于:" pwd echo "其中以vml开头的文件包括:" ls -lh vml* [root@c7-1 /]# bash /home/test.sh 当前目录位于: /boot 其中以vml开头的文件包括: -rwxr-xr-x. 1 root root 5.7M 7月 22 01:24 vmlinuz-0-rescue-88592b0b2e2b49fab4e71eedc23b1998 -rwxr-xr-x. 1 root root 5.7M 8月 23 2017 vmlinuz-3.10.0-693.el7.x86_64
类型 | 设备文件 | 文件描述编号 | 默认设备 |
---|---|---|---|
标准输入 | /dev/stdin | 0 | 键盘 |
标准输出 | /dev/stdout | 1 | 显示器 |
标准错误输出 | /dev/stderr | 2 | 显示器 |
[root@c7-1 home]# vim passwd.txt 12345 [root@c7-1 home]# passwd --stdin zhangsan < passwd.txt //把passwd.txt的数据12345,重定向输入到passwd zhangsan用户下,即修改zhangsan密码为12345 更改用户 zhangsan 的密码 。 passwd:所有的身份验证令牌已经成功更新
[root@c7-1 home]# echo "123456" > passwd.txt //重定向输出,将123456输入到passwd.txt [root@c7-1 home]# cat passwd.txt 123456 [root@c7-1 home]# cat passwd.txt 12345 [root@c7-1 home]# echo "123456789" >> passwd.txt //将123456789追加输出到passwd.txt尾部 [root@c7-1 home]# cat passwd.txt 12345 123456789
[root@c7-1 home]# ls /tmp/ xxx 2>1.txt [root@c7-1 home]# cat 1.txt ls: 无法访问xxx: 没有那个文件或目录 [root@c7-1 home]# ls /tmp/ www 2>>1.txt [root@c7-1 home]# cat 1.txt ls: 无法访问xxx: 没有那个文件或目录 ls: 无法访问www: 没有那个文件或目录 #发现错误信息变成了两行
[root@c7-1 home]# ls /etc/passwd xxx &>> 1.txt [root@c7-1 home]# cat 1.txt ls: 无法访问xxx: 没有那个文件或目录 /etc/passwd
&表示等同于的意思 1>&2 把标准输出重定向到标准错误 2>&1 把标准错误重定向到标准输出 [root@c7-1 home]# ls /etc/passwd xxx > 1.txt 2>&1 [root@c7-1 home]# cat 1.txt ls: 无法访问xxx: 没有那个文件或目录 /etc/passwd #把标准输出 输出到1.txt 再把1.txt的标准错误重定向到标准输出 [root@c7-1 home]# ls /etc/passwd xxx 2> 1.txt 1>&2 [root@c7-1 home]# cat 1.txt ls: 无法访问xxx: 没有那个文件或目录 /etc/passwd #把标准错误输出到1.txt 再把1.txt的标准输出重定向到标准错误
把它看作"黑洞",所有写入它的内容都会永远丢失.而尝试从它那儿读取内容则什么也读不到。然而 /dev/null 对命令行和脚本都非常的有用
[root@c7-1 home]# echo "123456" > /dev/null [root@c7-1 home]# cat /dev/null [root@c7-1 home]# #什么也看不到
[root@c7-1 home]# grep "/bin/bash$" /etc/passwd | awk -F: '{print $1,$7}' root /bin/bash lz /bin/bash zhangsan /bin/bash #检索调用/bin/bash的第一行和第七行用户 [root@c7-1 home]# df -Th | grep "/$" | awk '{print $6}' 19%
重定向与管道操作是 shell环境中十分常用的功能,若能够熟练掌掘并灵活运用,将有助于编写代码简洁组功能强大的shell脚本程序
变量名:使用固定的名称,由系统预设或用户定义
变量值:能够根据用户设置、系统环境的变化而变化
Bash中的变量操作相对比较简单,不像其他高级编程语言(如C/C++、Java等)那么复杂。在定义一个新的变量时,一般不需要提前进行声明,而是直接指定变量名称并赋给初始值(内容)即可
格式:
变量名=变量值
等号两边没有空格。变量名称需以字母或下划线开头,名称中不要包含特殊字符
unset 变量名 [root@c7-1 home]# unset Pr
通过在变量名称前添加前导符号"$",可以引用一个变量的值,使用echo 命令可以查看变量,可以在一条 echo命令中同时查看多个变量值
格式: echo $变量名 [root@c7-1 home]# a=lz //定义变量 [root@c7-1 home]# echo $a //查看变量的值 lz [root@c7-1 home]# b=666 [root@c7-1 home]# echo $a $b lz 666 #当变量名称容易和紧跟其后的其他字符相混淆时, #需要添加大括号“{}”将其括起来,否则将无法确定正确的变量名称。 #对于未定义的变量,将显示为空值 [root@c7-1 home]# echo $Pr Python [root@c7-1 home]# echo ${Pr}2.7.20 Python2.7.20 [root@c7-1 home]# echo ${test}RMB RMB
[root@c7-1 home]# echo -n hello //-n表示不换行输出 hello[root@c7-1 home]# [root@c7-1 home]# echo -e "hello\n" //-e输出转义字符,转义后的内容将输出到屏幕上;\n 换行 hello [root@c7-1 home]# echo -e "hello\t" // \t 转义后插入tab,即制表符 hello #注:\转义符,跟在\之后的特殊符号将失去特殊含义,变为普通字符。 #如\$将输出"$"符号,而不当做是变量引用
双引号允许通过$符号引用其他变量值,双引号主要起界定字符串的作用,特别是当要赋值的内容中包含空格时,必须以双引号括起来;其他情况下双引号通常可以省略
#当内容中有空格 [root@c7-1 home]# echo "hello world" hello world #当以变量的值进赋值 [root@c7-1 home]# version=2 [root@c7-1 home]# pyver="python $version" [root@c7-1 home]# echo $pyver python 2
禁止引用其他变量值,$视为普通字符
但赋值内容中包含单引号 ‘’ 时,需使用’符号进行转义,以免冲突。
[root@c7-1 ~]# pyver='python $version' [root@c7-1 ~]# echo $pyver python $version
反撇号主要用于命令替换,允许将执行某个命令的屏幕输出结果赋值给变量。
反撇号括起来的范围内必须是能够执行的命令行,否则将会出错
[root@c7-1 ~]# ls -lh `which useradd` -rwxr-x---. 1 root root 116K 11月 6 2016 /usr/sbin/useradd #先通过 which useradd命令查找出 useradd 命令的程序位置,然后根据查找结果列出文件属性 [root@c7-1 ~]# time=`date +%T` [root@c7-1 ~]# echo $time 13:56:41 #使用反撇号难以在一行命令中实现嵌套命令替换操作, #这时可以改用 "$()" 来代替反撇号操作,以解决嵌套的问题 [root@c7-1 ~]# rpm -qc $(rpm -qf $(which useradd)) /etc/default/useradd /etc/login.defs
除了上述赋值操作以外,还可以使用 Bash 的内置命令read来给变量赋值。
用来提示用户输入信息,从而实现简单的交互过程。执行时将从标准输入设备(键盘)读入
一行内容,并以空格为分隔符,将读入的各字段依次赋值给指定的变量(多余的内容赋值给
最后一个变量)。若指定的变量只有一个,则将整行内容赋值给此变量。
交互定义变量 -p 提示用户的信息 -n 定义字符数 -s 不显示用户输入的内容,常用于输入密码 -t 定义超时时间,超过多长时间没输出自动退出 [root@c7-1 ~]# read -p "请输入你的姓名:" name 请输入你的姓名:dashiji [root@c7-1 ~]# echo $name dashiji [root@c7-1 ~]# read -s -p "请输入你的密码:" pass 请输入你的密码:[root@c7-1 ~]# [root@c7-1 ~]# echo $pass 123
[root@c7-1 ~]# echo 192.168.3.3 > ip.txt [root@c7-1 ~]# cat ip.txt 192.168.3.3 [root@c7-1 ~]# read -p "请输入你的IP:" IP < ip.txt [root@c7-1 ~]# echo $IP 192.168.3.3
默认情况下,新定义的变量只在当前的 Shell环境中有效,因此称为局部变量,当进入子程序或新的子Shell环境时,局部变量将无法再使用
#格式1: export 变量名 #格式2: export 变量名=变量值 #两种格式可以混合使用
为了使用户定义的变量在所有的子Shell环境中能够继续使用,减少重复设置工作,可以通过内部命令export
将指定的变量导出为全局变量。用户可以同时指定多个变量名称作为参数(无须使用"s"符号),变量名之间以空格分隔
[root@c7-1 ~]# name=zhangsan [root@c7-1 ~]# test=18 [root@c7-1 ~]# echo $name $test zhangsan 18 [root@c7-1 ~]# bash //进入到子shell环境 [root@c7-1 ~]# echo $name $test //发现是空的 [root@c7-1 ~]# exit exit [root@c7-1 ~]# export name test //导出为全局变量 [root@c7-1 ~]# bash [root@c7-1 ~]# echo $name $test //子程序引用全局变量 zhangsan 18
使用export导出全局变量的同时,也可以为变量进行赋值,这样在新定义全局变量时就不需要提前进行赋值了,env查看用户当前环境变量
[root@c7-1 ~]# export abc=123 [root@c7-1 ~]# env abc=123
#格式: expr 变量1 运算符 变量2 [运算符 变量3]...
加法运算:+ 减法运算:- 乘法运算:\* 除法运算:/ 求模(取余)运算:%
[root@c7-1 ~]# expr 1+1 1+1 [root@c7-1 ~]# expr 1 + 1 2 [root@c7-1 ~]# expr 12 \* 2 24 [root@c7-1 ~]# expr 12 / 2 6 [root@c7-1 ~]# x=42 [root@c7-1 ~]# y=36 [root@c7-1 ~]# expr $x + 5 47 [root@c7-1 ~]# sum=`expr $y \* $y \* 2` [root@c7-1 ~]# echo $sum 2592 [root@c7-1 ~]# vim shuzi.sh #!/bin/bash read -p "请输入第一个数字:" num1 read -p "请输入第二个数字:" num2 sum=`expr $num1 + $num2` echo "求和数:$sum" [root@c7-1 ~]# bash shuzi.sh 请输入第一个数字:22 请输入第二个数字:22 求和数:44 [root@c7-1 ~]# echo $[10+10] 20 [root@c7-1 ~]# echo $((1+1)) 2
由系统提前创建,用来设置用户的工作环境
配置文件:/etc/profile、~/.bash_profile
使用env 命令可以查看到当前工作环境下的环境变量,对于常见的一些环境变量应了解其各自的用途。例如,变量USER表示用户名称,HOME表示用户的宿主目录,LANG表示语言和字符集,PWD表示当前所在的工作目录,
PATH 表示命令搜索路径等、RANDOM表示随机数,会返回0-32767的整数,USER表示当前账户的账户名称等,一般都用全大写定义,注意和自定义变量区分
[root@c7-1 ~]# echo $PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin [root@c7-1 ~]# echo $HOME /root [root@c7-1 ~]# echo $USER root [root@c7-1 ~]# echo $LANG zh_CN.UTF-8
PATH变量用于设置可执行程序的默认搜索路径,当仅指定文件名称来执行命令程序时,Linux系统将在 PATIH变量指定的目录范围查找对应的可执行文件,如果找不到则会提示"command not found"。
[root@c7-1 ~]# fs.sh bash: fs.sh: 未找到命令... [root@c7-1 ~]# PATH="$PATH:/root" [root@c7-1 ~]# fs.sh 123456
[root@c7-1 ~]# name=11111 [root@c7-1 ~]# readonly name [root@c7-1 ~]# echo $name 11111 [root@c7-1 ~]# name=2222 -bash: name: 只读变量 [root@c7-1 ~]# unset name -bash: unset: name: 无法反设定: 只读 variable [root@c7-1 ~]# #重启则失效,可以修改
[root@c7-1 ~]# vim user.sh #!/bin/bash useradd $1 echo $2 | passwd --stdin $1 [root@c7-1 ~]# bash user.sh lisi 123 //lisi为第一个位置参数,$1 ;123为第二个位置参数 $2 更改用户 lisi 的密码 。 passwd:所有的身份验证令牌已经成功更新
[root@c7-1 ~]# vim fuhao.sh #!/bin.bash echo $1 echo "$0 表示当前执行的脚本或程序的名称" echo "$# 表示命令行中位置的参数个数" echo "$* 所有位置参数的内容,这些内容是当做一个整体" echo "$@ 表示列出所有未知参数,但是是以单个的形式列出 [root@c7-1 ~]# bash fuhao.sh 1 2 3 4 1 fuhao.sh 表示当前执行的脚本或程序的名称 4 表示命令行中位置的参数个数 1 2 3 4 所有位置参数的内容,这些内容是当做一个整体 1 2 3 4 表示列出所有未知参数,但是是以单个的形式列出 #理解 $* 和 $@ 的区别 $* :把所有参数看成以空格分隔的一个字符串整体(单字符串)返回,代表"$1 $2 $3 $4"。 $@ :把各个参数加上双引号分隔成n份的参数列表,每个参数作为一个字符串返回,代表"$1" "$2" "$3" "$94"。 $* :是将参数全部当做一个整体 $@ :是将参数每一个都当做单独的个体 set:查看系统所有的变量,包括环境变量和自定义变量(没有单独查看自定义变量的命令,可以set管道过滤)