拒绝低效率学习!Shell脚本讲解 从入门到精通

316 阅读7分钟

image-20201205125756624

Shell编程概述

本shell教程出自:优极限

Shell名词解释

  • Kernel

    • Linux内核主要是为了和硬件打交道
  • Shell

    • 命令解释器(command interpreter)
    • 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)
  • #! 声明

    • 告诉系统其后路径所指定的程序即是解释此脚本文件的 Shell 程序
    • #!/bin/bash
      echo "Hello World !"
      

Shell脚本的执行

  • 输入脚本的绝对路径或相对路径

    • /root/helloworld.sh
    • ./helloworld.sh
    • 执行的必须是一个可执行文件
  • bash或sh +脚本

    • sh helloworld.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="hello world 1"
      str2='hello world 2'# 字符串拼接--双引号
      name='sunwukong'
      name1="hello, "$name" !"
      name2="hello, ${name} !"# 字符串拼接--单引号
      passwd='123456'
      passwd1='hello, '$passwd' !'
      passwd2='hello, ${passwd} !'
      echo $passwd2  # hello, ${passwd} !# 字符串的长度
      email="123456@qq.com"
      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  #####
    ​
    ​
    # 特殊的多行注释
    ​
    :<<EOF
    注释内容...
    注释内容...
    注释内容...
    EOF
    ​
    :<<!
    注释内容...
    注释内容...
    注释内容...
    !
    

Shell参数传递

  • 执行 Shell 脚本时,向脚本传递参数,脚本内获取参数的格式为: $nn 代表一个数字
  • 参数处理参数说明
    $#传递到脚本的参数个数
    $*以一个单字符串显示所有向脚本传递的参数。
    $$脚本运行的当前进程ID号
    $!后台运行的最后一个进程的ID号
    $?显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。
    $0执行的文件名
  • #!/bin/bashecho "Shell 传递参数实例!";
    echo "执行的文件名:$0";
    echo "第一个参数为:$1";
    echo "第二个参数为:$2";
    echo "第三个参数为:$3";
    ​
    # ./hello.sh 11 22 33 44
    

Shell高级进阶

本shell教程出自:优极限

Shell运算符

  • 运算符的分类

    • 算数运算符
    • image-20201205162731120
    • 关系运算符
    • image-20201205162742536
    • 布尔运算符
    • image-20201205162802200
    • 字符串运算符
    • image-20201205162820041
    • 文件测试运算符
    • image-20201205162840963

算数运算符

定时任务

  • 在系统服务中心,crond负责周期任务

    • systemctl status crond.service
  • 添加任务,编辑当前用户的任务列表

    • crontab -e
  • 编辑任务

    • 星 星 星 星 星 command 分 时  日  月  周 命令 第1列表示分钟0~59 每分钟用*或者 */2表示 第2列表示小时0~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 restart
      上面的例子表示每月11022日的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 : 0023 : 00之间每隔30分钟重启apache。
      ​
      0 23 * * 6 /usr/local/etc/rc.d/lighttpd restart
      上面的例子表示每星期六的11 : 00 pm重启apache。
      ​
      * */2 * * * /usr/local/etc/rc.d/lighttpd restart
      每两小时重启apache
      ​
      * 23-7/1 * * * /usr/local/etc/rc.d/lighttpd restart
      晚上11点到早上7点之间,每隔一小时重启apache
      ​
      0 11 4 * mon-wed /usr/local/etc/rc.d/lighttpd restart
      每月的4号与每周一到周三的11点重启apache
      ​
      0 4 1 jan * /usr/local/etc/rc.d/lighttpd restart
      一月一号的4点重启apache
      ​
      --(功能描述:显示年月日时分秒)
      date "+%Y%m%d%H%M%S" 
      
  • 重启crontab,使配置生效

    • systemctl restart crond.service
  • 通过crontab -l

    • 查看当前的定时任务
  • 查看任务的历史

    • vim /var/spool/mail/root
  • 清除任务

    • crontab -r

虚拟机初始化脚本

#!/bin/bash
## -bash: ./bdp.sh: /bin/bash^M: bad interpreter: No such file or directory
## vim或者vi的命令模式下,输入命令  set fileformat=unix 即可解决换行问题
## sed -i "s/\r//" init.sh
echo -e "\e[1;31m【----------------------------------------在opt和var创建bdp文件夹】\e[0m"
sleep 1
mkdir -p /opt/bdp
mkdir -p /var/bdp
mkdir -p /usr/local/script
​
echo -e "\e[1;31m【----------------------------------------禁用防火墙】\e[0m"
sleep 1
systemctl stop firewalld
systemctl disable firewalld
systemctl status firewalld
​
echo -e "\e[1;32m【----------------------------------------修改selinux】\e[0m"
sleep 1
sed -i '/^SELINUX=/c SELINUX=disabled' /etc/selinux/config
​
echo -e "\e[1;32m【----------------------------------------安装wget】\e[0m"
sleep 1
yum install wget -y
​
echo -e "\e[1;33m【----------------------------------------修改yum源】\e[0m"
sleep 1
mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup
wget -O /etc/yum.repos.d/CentOS-Base.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 net-tools telnet perl  -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 1
echo "192.168.88.100 basenode" >> /etc/hosts
echo "192.168.88.101 node01" >> /etc/hosts
echo "192.168.88.102 node02" >> /etc/hosts
echo "192.168.88.103 node03" >> /etc/hosts
echo -e "\e[1;34m【----------------------------------------安装JDK】\e[0m"
sleep 1
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"
sleep 1
tar -zxf apache-tomcat-8.5.47.tar.gz
mv apache-tomcat-8.5.47 /opt/bdp/
echo -e "\e[1;35m【----------------------------------------安装Mysql】\e[0m"
sleep 1
rpm -e --nodeps `rpm -qa | grep mariadb`
​
tar -xvf mysql-5.7.28-1.el7.x86_64.rpm-bundle.tar
rpm -ivh mysql-community-common-5.7.28-1.el7.x86_64.rpm
rpm -ivh mysql-community-libs-5.7.28-1.el7.x86_64.rpm
rpm -ivh mysql-community-client-5.7.28-1.el7.x86_64.rpm
rpm -ivh mysql-community-server-5.7.28-1.el7.x86_64.rpm
​
systemctl start mysqld
systemctl enable mysqld
​
temppasswd=`grep "A temporary password" /var/log/mysqld.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;
update user set  host='%' where user = 'root';
commit;
quit
EOF
​
systemctl restart mysqld
​
echo -e "\e[1;35m【----------------------------------------安装Nginx】\e[0m"
sleep 1
echo -e "\e[1;36m【----------------------------------------设置开机启动项】\e[0m"
sleep 1
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 /usr/local/script/auto_ntpdate.sh
​
echo '/usr/local/script/auto_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 1
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 1
shutdown -h now

虚拟机相互免秘钥

本shell教程出自:优极限

##三台主机分别生成秘钥123】ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa
​
##host验证123】vim /etc/ssh/ssh_config  在最后添加
​
  StrictHostKeyChecking no
  UserKnownHostsFile /dev/null
​
##将秘钥分别拷贝给自己和别人123】ssh-copy-id -i ~/.ssh/id_rsa.pub root@node01
【123】ssh-copy-id -i ~/.ssh/id_rsa.pub root@node02
【123】ssh-copy-id -i ~/.ssh/id_rsa.pub root@node03
​
123456##关闭主机拍摄快照
power off