Shell编程概述(THE bourne-again shell)
Shell名词解释(外壳,贝壳)
Kernel
Linux内核主要是为了和硬件打交道
Shell
命令解释器(command interperter)
Shell是一个用C语言编写的程序,他是用户使用Linux的桥梁。Shell既是一种命令语言,又是一种程序设计语言。
Shell是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。
Shell两大主流
sh:
Bourne shell (sh) ,Solaris,hpux默认shell
Bourne again shell (bash) ,Linux系统默认shell
csh:
C shell(csh)
tc shell(tcsh)
window里面是.bat结尾
#!声明
告诉系统其后路径所制定的程序即是解释此脚本文件的Shell程序
#!/bin/bash(bash比sh大)
echo "Hello world !"
Shell脚本的执行
输入脚本的绝对路径或相对路径
/root/helloworld.sh
./helloworld.sh (可执行的是一个绿的,只有这种需要改,chmod u+x helloworld.sh)
执行的必须是一个可执行的文件
bash或sh +脚本
当脚本没有x权限时,root和文件所有者通过该方式可以正常执行
在脚本的路径前面加"."或source
source helloworld.sh
区别
第一种和第二种会新开一个bash,不同bash中的变量无法共享
第三种是在同一个shell里面执行的
export:可以将当前进程的变量传递给子进程去使用
将来配置profile的时候,所有的变量前面必须加export
Shell基础入门
shell变量
定义变量时,变量名不加美元符号
命名只能使用英文字母,数字和下划线,首个字符不能以数字开头。
中间不能有空格,可以使用下划线。
不能使用标点符号。
不能使用bash里的关键字(可用help命令查看保留关键字)
变量的类型
局部变量
局部变量在脚本或命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量。
环境变量
所有的程序,包括shell启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行。
Shell变量
shell变量是由shell程序设置的特殊变量。shell中有一部分是环境变量,有一部分是局部变量。
变量的声明
name="zhangsan"
for file in 'ls /etc'
或
for file in $(ls /etc)
变量的调用
echo $name
echo ${name}
for skill in Ada Coffe Action Java;do
echo "I am good at ${skill}Script"
done
只读变量 /bin/sh: NAME: This variable is read only.
url="https://www.google.com"
readonly url
url="https://www.runoob.com"
删除变量
unset name
Shell的字符串
字符串是shell编程中最常用最有用的数据类型,字符串可以用单引号,也可以用双引号,也可以不用引号。
单引号:
单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的。
单引号字符串中不能出现单独一个的单引号,但可成对出现,作为字符串拼接使用。
双引号:
双引号里可以有变量
双引号里可以出现转义字符
声明字符串
str1="helloworld 1"
str2='hello world 2'
字符串拼接--双引号
name='helloworld'
name1="hello, "$name" !"
name2="hello, ${name} !"
字符串拼接--单引号
passwd='123456'
passwd1='hello, '$passwd' !'
passwd2='hello, ${passwd} !'
echo $passwd2 # hello, ${passwd} !
字符串的长度
echo ${#email}
echo ${email:1:4}
Shell数组
bash支持一维数组(不支持多维数组),并且没有限定数组的大小。
数组元素的下标由0开始编号。获取数组中的元素要利用下标,下标可以是整数或算术表达式,其值应大于或等于0。
#定义数组 括号来表示数组 ,数组元素用"空格"符号分割开
数组名=(值1,值2 。。。 值n)
favs=("足球" "篮球" "乒乓球" "保龄球")
读取数组 ${数组名[下标]}
fav=${favs[1]}
使用@符号可以获取数组中的所有元素
echo ${favs[@]}
获取数组的长度
length1=${#favs[@]}
length2=${#favs[*]}
shell的注释
以#开头的行就是注释,会被解释器忽略。
通过每一行加一个#号设置多行注释。
这是一个注释
#author
#site:
###服务器配置-start####
#####服务器配置-end###
特殊的多行注释
:<<EPF
EOF(虽然别的字母也可以,但是要上下相同,但是最好写这个)
:<<!
!
shell参数传递
1,执行shell脚本时,向脚本传递参数,脚本内获取参数的格式为: $n. n代表一个数字
参数处理 参数说明
$# 传递到脚本的参数个数
$* 以一个单字符串显示所有向脚本传递的参数
脚本运行的当前进程的ID号 $! 后台运行的最后一个进程的ID号 $? 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误 $0 执行的文件名 #! /bin/bash echo "Shell 传递参数实例!"; echo "执行的文件名:$0"; echo "第一个参数为:$1"; echo "第二个参数为:$2"; echo "第三个参数为:$3"; #./hello.sh 11 22 33 44 ## Shell高级进阶 ### 1.Shell运算符 ##### 运算符的分类 ###### 算术运算符 运算符:说明:举例 +:加法:'expr $a + $b' (esc下面哪个按键(包住的就是命令)) -:减法: \*:乘法c /:除法: %:取余: =:赋值: ==:相等。用于比较两个数字。相同则返回true。: !=:不相等。用于比较两个数字,不相同则返回true。: #! /bin/bash a=10 b=20 val='wxpr $a + $b' echo "a+b : $val" val=' expr $a - $b ' echo "a -b : $val" val='expr $a \\\* $b' echo "a \* b : $val " val='expr $a / $b' echo "a / b : $val " val='expr $a % $b' echo "a % b : $val " if \[ $a == $b \] then echo "a 等于 b" fi if \[ $a != $b \] then echo " a 不等于 b " fi ###### 关系运算符 关系运算符只支持数字,不支持字符串,除非字符串的值是数字。 #! /bin/bash a=10 b=20 if \[ $a -eq $b\] then echo "$a -eq $b : a 等于 b" else echo "$a -eq $b : a 不等于 b" fi if \[ $a -ne $b\] then echo "$a -ne $b : a 不等于 b" else echo "$a -ne $b : a 等于 b" fi if \[ $a -gt $b\] then echo "$a -gt $b : a 大于 b" else echo "$a -gt $b : a 不大于 b" fi if \[ $a -lt $b\] then echo "$a -lt $b : a 小于 b" else echo "$a -lt $b : a 不小于 b" fi if \[ $a -ge $b\] then echo "$a -ge $b : a 大于或等于 b" else echo "$a -ge $b : a 小于 b" fi if \[ $a -le $b\] then echo "$a -le $b : a 小于或等于 b" else echo "$a -le $b : a 大于 b" fi ###### 布尔运算符 #! /bin/bash a=10 b=20 if \[ $a != $b \] then echo "$a != $b : a 不等于 b" else echo "$a == $b : a 等于 b" fi if \[ $a -lt 100 -a $b -gt 15 \] then echo "$a 小于 100 且 $b 大于 15 : 返回true" else echo "$a 小于 100 且 $b 大于15 : 返回false " fi if \[ $a -lt 100 -o $b -gt 100 \] then echo "$a 小于 100 或 $b 大于100 : 返回true " else echo "$a 小于100 或 $b 大于 100 : 返回false " fi if \[ $a -lt 5 -o $b -gt 100 \] then echo "$a 小于5 或 $b 大于100 : 返回true " else echo "$a 小于 5 或 $b 大于 100 : 返回 false" fi ###### 逻辑运算符 #! /bin/bash a=10 b=20 if \[\[ $a -lt 100 \&\& $b -gt 100 \]\] then echo "返回 true" else echo "返回 false" fi if \[\[ $a -lt 100 \|\| $b -gt 100 \]\] then echo "返回 true" else echo "返回 false" fi ###### 字符串运算符 #! /bin/bash a="abc" b="efg" if \[ $a = $b \] then echo "$a = $b : a 等于 b" else echo "$a = $b : a 不等于 b" fi if \[ $a != $b \] then echo "$a != $b : a 不等于 b" else echo "$a != $b : a 等于 b" fi if \[ -z $a \] then echo " -z $a :字符串长度为0" else echo "-z $a :字符串长度不为0" fi if \[ -n $a \] then echo " -n $a :字符串长度不为0" else echo "-n $a :字符串长度为0" fi if \[ $a \] then echo " $a :字符串长度不为空" else echo " $a :字符串长度为空" fi ###### 一些运用: yum info ntp \&\& ntpdate cn.ntp.org.cn(后面这个是ntp的一个命令) yum info ntp \|\| yum install ntp -y yum info ntp \>\> /dev/null ###### 文件测试运算符 #! /bin/bash file="/var/node/test.sh" if \[ -r $file\] then echo"文件可读" else echo "文件不可读" fi if \[ -x $file \] then echo "文件可写" else echo "文件不可写" fi if \[ -x $file \] then echo "文件可执行" else echo "文件不可执行" fi if \[ -f $file \] then echo "文件是个目录" else echo "文件为特殊文件" fi if \[ -d $file \] then echo "文件是个目录" else echo "文件不是个目录" fi if -s 文件是否为空 -e文件存在不存在 shift+insert(两个按键)往vi的文件里面粘贴。按鼠标的右键可以看见快捷键 #### echo打印数据 Shell 的echo 指令与PHP的echo指令类似,都是用于字符串输出。 显示普通字符串 echo "Hello World" 显示转义字符 echo "\\"Hello world"" 显示变量 name="zhangsan" echo "$name Hello world" 显示换行 echo -e "OK! \\n" echo "Hello World" 显示不换行 echo -e"OK! \\c" echo "Hello World" 显示结果定向至文件 echo "Hello World" \> myfile 原样输出字符串 echo '$name\\" ' 显示命令执行结果 echo \`date\` ### test命令 Shell中的test命令用于检查某个条件是否成立,它可以进行数值,字符和文件三个方面的测试。 数字 参数:说明 -eq:等于则为真 -ne:不等于则为真 -gt:大于则为真 -lt:小于则为真 -le:小于等于则为真 字符串: 参数:说明 =:等于则为真 !=:不相等则为真 -z字符串:字符串的长度为零则为真 -n字符串:字符串的长度不为零则为真 文件测试 参数:说明 -e文件名:如果文件存在则为真 -r文件名:如果文件存在且可读则为真 -w文件名:如果文件存在且可写则为真 -x文件名:如果文件存在且可执行则为真 -s文件名:如果文件存在且至少有一个字符则为真 -d文件名:如果文件存在且为目录则为真 -f文件名:如果文件存在且为普通文件则为真 -c文件名:如果文件存在且为字符型特殊文件则为真 -b文件名:如果文件存在且为特殊文件则为真 #比较 num1=100 num2=100 if test $\[num1\] -eq $\[num2\] then echo '两个数相等!' else echo '两个数不相等!' fi ### Shell流程控制 ##### if if condition1 then command1 elif condition2 then command2 else commendN fi a=10 b=20 if \[ $a == $b \] then echo "a 等于 b" elif \[ $a -gt $b \] then echo " a 大于 b " elif \[ $a -lt $b \] then echo " a 小于 b " else echo "没有符合的条件" fi ##### case Shell case语句为多选择语句,可以用case语句匹配一个值与一个模式,如果匹配成功,执行相匹配的命令 case 值 in 模式1 command1 command2 ... commandN ;; 模式2 command1 command2 ... commandN ;; esac echo ' 输入1到4之间的数字 ' echo '你输入的数字为:' read num case $num in 1) echo ' 你选择了 1 ' ;; 2) echo ' 你选择了 2 ' ;; 3) echo ' 你选择了 3 ' ;; 4) echo ' 你选择了 4 ' ;; \*) echo ' 你没有输入1到4之间的数字 ' (\*就是匹配所有) ;; esac ##### for 当变量值在列表里,for循环即执行一次所以命令,使用变量名获取列表中的当前取值 命令可为任何有效的shell命令和语句。in列表可以包含替换、字符串和文件名。 in列表是可选的,如果不用它,for循环使用命令行的位置参数。 for var in item1 item2 ... itemN do command1 command2 ... commandN done for loop in 1 2 3 4 5 do echo "The value is : $loop" done for str in 'This is a string','hello moto' do echo $str done ##### while循环 while循环用于不断执行一系列命令,也用于从输入文件中读取数据;命令通常为测试条件。 while condition do command done #Bash let 命令,它用于执行一个或多个表达式,变量计算中不需要加上$来表示本变量 #!/bin/bash int=1 while(( $int\<=5 )) do echo $int let "int++" done #无限循环 while true do comand done ##### break break命令允许跳出所有循环(终止执行后面的所有循环) #!/bin/bash while : do echo -n "输入 1 到 5 之间的数字;" read aNum in 1\|2\|3\|4\|5) echo "你输入的数字为 $aNum!" ;; \*) echo "你输入的数字不是1到5之间!游戏结束" break ;; esac done ##### continue countinue命令不会跳出所有循环,仅仅跳出当前循环。 #!/bin/bash while : do echo -n "输入1到5之间的数字:" read aNum case $aNum in 1\|2\|3\|4\|5) echo "你输入的数字为 $aNum!" ;; esac done ##### Shell函数 linux shell 可以用户定义函数,然后在shell脚本中随便调用。 可以带function fun()定义,也可以直接fun()定义,不带任何参数。 参数返回,可以显示加:return 返回,如果不加,将以最后一条命令运行结果,作为返回值。return后跟数值n(0-255) #!/bin/bash ##第一个函数 demoFun(){ echo "这是我的第一个shell函数" } echo "--------函数开始执行------" demoFun echo"----------函数执行完毕-----------" 函数返回值-------------------- funWithReturn(){ echo "这个函数会对输入的这两个数字进行相加运算。。。" echo "输入第一个数字:" read aNum echo "输入第二个数字:" readanotherNum echo "两个数字分别为 $aNum 和 $anotherNum ! " return $(($aNum+$anotherNum)) } funWithReturn #函数返回值在调用该函数后通过 $? 来获得。 echo "输入两个数字之和为$? !" 函数参数------------------------------ funWithParam(){ scho "第一个参数为 $1 !" scho "第2个参数为 $2 !" scho "第10个参数为 $10 !" scho "第10个参数为 ${10} !" scho "第11个参数为 ${11} !" scho "参数总数有$# 个!" scho "作为一个字符串输出所有参数 $\* !" } funWithParam 1 2 3 4 5 6 7 8 9 ## 系统任务设置 ### 系统启动流程 启动计算机的硬件(BIOS) 1读取时间 2选择对应的启动模式(USB HDD EFI) 如果是Linux系统,回去找/boot目录,引导这个系统启动 计算机系统开始启动,读取初始化配置文件 vim /etc/inittab 启动时控制着计算机的运行级别runlevel 0 halt(关机) 1 Single user mode(单用户模式) 2Multiuser,without NFS(多用户模式,但是无网络状态) FS --\>FileSystem 3Full multiuser mode(多用户完整版模式)、 4unused(保留模式) 5X11(用户界面模式) 6reboot(重启模式) id:3:initdefault: 默认runlevel为3 以runlevel=3开始启动对应的服务和组件 开始默认引导公共的组件或者服务 vim /etc/rc.d/rc.sysinit (主板决定BIOS) 开始加载对应runlevel的服务 vi /etc/rc3.d/ K:关机时需要关闭的服务 S:启动时需要开启的服务 数字代表了开启或者关闭的顺序。 所有的文件都是软链接,链接的地址为 /etc/init.d 当启动完毕,所有的服务也被加载完成。 ### 系统服务 我们可以使用chkconfig命令查看当前虚拟机的服务 通过查看可以得知不同的级别对应到每一个服务确定本次开机自动启动。 开机结束后,我们需要使用service(Centos6)Systemctl(Centos7)命令控制服务的开启或关闭。 ### 开机自启动服务 rc.local 首先创建脚本存放的文件夹 mkdir -p /usr/local/scripts 在文件夹中创建脚本文件 vim hello.sh 给与执行权限 去/etc/rc.d/rc.local文件中添加脚本的绝对路径。 给予rc.local执行权限 chkconfig 创建开机自启动脚本文件 vim schoolntpdate.sh #!/bin/bash #chkconfig: 12345 88 99 #description:auto_run 往local里面写路径的时候,可以在底行模式验证路径 开机自启动同步时间 yum info ntp \&\& ntpdate cn.ntp.org.cn 给其设置执行权限 chmod u+x schoolntpdate.sh 将脚本拷贝到 /etc/init.d目录下 cp schoolntpdate.sh /etc/init.d 添加到服务 chkconfig --add /etc/init.d/schoolntpdate.sh 重启服务 reboot ### 定时任务 (win里是艾特和艾瑞) 在系统服务中心,crond负责周期任务 systemctl status crond.service 添加任务,编辑当前用户的任务列表 crontab -e 编辑任务 星星星星星 command(定义一个时间)(你想干什么) 分 时 日 月 周 命令 第1列表示分钟1\~59 每分钟用\*或者\*/1表示(\*是任意。\*/2每隔两分钟) 第2列表示小时1\~23 (0表示0点) 第3列表示日期1\~31 第4列表示月份1\~12 第5列标识号星期0\~6 (0表示星期天) 第6列要运行的命令 \*:表示任意时间都,实际上就是每的意思。可以代表00-23小时或者00-12每月或者00-59分 -:表示区间,是一个范围,00 17-19\*\*\*cmd ,就是每天17,18,19点的整点执行命令 ,:是分割时段,30 3,19,21\*\*\*cmd,就是每天凌晨3和晚上19,21点的半点时刻执行命令 /n: 表示分割,可以看成除法,\*/5\*\*\*\*cmd,每隔五分钟执行一次。 30 21 \* \* \* /usr/local/etc/rc.d/lighttpd restart 上面的例子表示每晚21:30重启apache。 45 4 1,10,22 \* \* /usr/local/etc/rc.d/lighttpd testart 上面的例子表示每月1/10/22日的4:45重启apache 10 1 \* \* 6,0 /usr/local/etc/rc.d/lighttpd restart 上面的例子表示每周六,周日的1:10重启apache 0,30 18-23 \* \* \* /usr/local/etc/rc.d/lighttpd restart 上面的例子表示在每天的18:00到23:00之间每隔30分钟重启apache 0 23 \* \* 6 /usr/local/etc/rc.d/lighttpd restart 上面的例子表示每星期六的11:00pm重启apache \* \*/2 \* \* \* /usr/local/etc/rc.d/lighttpd restart 上面的例子表示每两个小时重启apache \* 23-7/1 \* \* \* /usr/local/etc/rc.d/lighttpd restart 晚上11点到早上起点每隔1小时重启apache 0 11 4 \* mon-wed /usr/local/etc/rc.d/lighttpd restart 每月的四号与每周一到周三的11点重启apache 0 4 1 jan \* /usr/local/etc/rc.d/lighttpd restart 一月一号的四点重启apache (功能描述:显示年月日时分秒) date "+%Y%m%d%H%M%S" 得到一个秒表示的时间 date "+%Y%m%d%H%M%S" \| mkdir -p dname=\`date "+%Y%m%d%H%M%S"\` mkdir -p $dname ll 重启crontab ,是配置生效 systemctl restart crond.service 通过crontab -l 查看当前的定时任务 查看任务的历史 vim /var/spool/mail/root 清除任务 crontab -r ##### 虚拟初始化脚本 #! /bin/bash ## -bash: ./luck.sh: /bin/bash\^M: bad interpreter: No such file or directory ## vim 或者vi的命令模式下,输入命令 set fileformat=unix 即可解决换行问题 echo -e "\\e\[1;31m【------------------------------------在opt和var创建lucky文件夹】\\e\[0m" sleep 5 mkdir -p /opt/luck mkdir -p /var/local/script mkdir -p /usr/local/scrip echo -e "\\e\[1;31m【------------------------------禁用防火墙】\\e\[0m" sleep 5 systemctl stop firewalld systemctl disable firewalld systemctl status firewalld echo -e "\\e\[1;32【------------------------------------修改selinux】\\e\[0m" sleep 5 sed -i '/\^SELINUX=/c SELINUX=disabled' /etc/selinux/config scho -e "\\e\[1;32m【------------------------安装wget】\\e\[0m" sleep 5 yum install wget -y echo -e"\\e\[1;33m【-----------------------修改yum源】\\e\[0m" sleep 5 mv /etc/yum.repos.d/CentOS-Base.repo.repo http://mirrors.aliyun.com/repo/Centos-7.repo yum clean all yum makecache echo -e "\\e\[1;33m【----------------------------安装常用软件】\\e\[0m" yum install man man-pages ntp vim lrzsz zip unzip telnet perl net-tools -y echo -e "\\e\[1;34m【------------------------------------同步系统时间】\\e\[0m" yum info ntp \&\& ntpdate cn.ntp.org.cn echo -e "\\e\[1;34m【------------------------------DNS域名配置】\\e\[0m" sleep 5 scho "192.168.188.100 basenode" \>\> /etc/hosts scho "192.168.188.101 bd1601" \>\> /etc/hosts scho "192.168.58.102 bd1602" \>\> /etc/hosts echo "192.168.58.103 bd1603" \>\> /etc/hosts echo -e "\\e\[1;34【----------------------------安装JDK】\\e\[0m" sleep 5 rpm -ivh jdk-8u231-linux-x64.rpm echo 'export JAVA_HOME=/usr/java/jdk1.8.0_231-amd64' \>\> /etc/profile echo 'export PATH=$JAVA_HOME/bin:$PATH' \>\> /etc/profile source /etc/profile echo -e "\\e\[1;35m【---------------------------安装Tomcat】\\e\[0m" sellp 5 tar -zxf apache-tomcat-8.5.47 /opt/lucky/ echo -e "\\e\[1;35【------------------------------安装Mysql】\\e\[0m" sleep 5 rpm -e --nodeps \`rpm -qa \| grep mariadb\` tar -xvf mysql-5.7.28-1.e17.x86_64.rpm-bundle.tar rpm -ivh mysql-community-common-5.7.28-1.e17.x86_64.rpm rpm -ivh mysql -community-libs-5.7.28-1.e17.x86_64.rpm rpm -ivh mysql -community-client-5.7.28-1.e17.x86_64.rpm rpm -ivh mysql -nommunity-server-5.7.28-1.e17.x86_64.rpm systemctl start mysqld systemctl enable mysqld temppasswd=\`grep "A temporary password" /var/log/mysql.log \| awk '{print $NF}'\` mysql -uroot -p$temppasswd --connect-expired-password \<\< EOF set global validate_password_policy=low; set global validate_password_length=6; alter user root@localhost identified by '123456'; use mysql; uodate user set host='%' where user = 'root'; commit; quit EOF systemctl restart mysqld echo -e "\\e\[1;35m【---------------------------安装Nginx】\\e\[0m" sleep 5 echo -e "\\e\[1;36m【-------------------------设置开机启动项】\\e\[0m" sleep 5 touch /usr/local/script/auto_ntpdate.sh echo '#!/bin/bash' \>\> /usr/local/script/auto_ntpdate.sh echo 'yum info ntp \&\& ntpdate cn.ntp.org.cn' \>\> /usr/local/script/auto_ntpdate.sh chmod u+x /etc/rc.local echo '/usr/local/script/auto_ntpdate.sh' \>\> /etc/rc.local chmod u+x /etc/rc.local echo '/usr/local/script/auto_ntp_ntpdate.sh' \>\> /etc/rc.local chmod u+x /etc/rc.local echo -e "\\e\[1;36m 【-------------------------------设置定时任务,更新时间】 \\e\[0m" echo -e "\\e\[1;36m【------------------------------------删除文件】\\e\[0m" sleep 5 rm -rf apache-tomcat-8.5.47.tar.gz rm -rf jdk-8u231-linux-x64.rpm rm -rf mysql\* rm -rf \*.sh echo -e "\\e\[1;36m【------------------------------------------------关闭计算器,拍快照】\\e\[0m" sleep 5 shutdown -h now ## 虚拟机相互免密钥 ##三台主机分别生成秘钥 【123】ssh-keygen -t rsa -P ' ' -f \~/ .ssh/id_rsa ##host验证 【123】 vim /etc/ssh/ssh_config 在最后添加 StrictHostKeyChecking no UseKnownHostsFile /dev/null ##将秘钥分别拷贝给自己和别人 【123】ssh-copy-id -i \~/ .ssh/id_rsa.pub root@bd1701 【123】ssh-copy-id -i \~/ .ssh/id_rsa.pub root@bd1703 【123】ssh-copy-id -i \~/ .ssh/id_rsa.pub root@bd1703 123456 ##关闭主机拍摄快照 power off