1. 前言

1.1 为什么学习shell编程

Shell脚本语言是实现Linux/UNIX系统管理及自动化运维所必备的重要工具,Linux/UNIX系统的底层及基础应用软件的核心大部分涉及Shell脚本的内容。
每一个合格的Linux系统管理员或运维工程师,都需要熟练的编写Shell脚本语言,并能够阅读系统及各类软件附带的Shell脚本内容。只有这样才能提升运维人员的工作效率,适应日益复杂的工作环境,减少不必要的重复工作,从而为个人的职场发展奠定较好的基础。

1.2 学好Shell编程所需的基础知识

    • 能够熟练使用vim编辑器,熟悉SSH终端。
    • 有一定的Linux命令基础,至少需要掌握80个以上Linux常用命令,并能够熟练使用它。
    • 要熟练掌握Linux正则表达式及三剑客命令(grep,sed,awk)
    • 常见的Linux网络服务部署、优化以及排错。
      • 例如:crond, nfs, rsync, inotify, lanmp, sersync, ssh, Memcached, MySQL等。

2. Shell脚本入门

2.1 什么是shell

  • Shell是一个命令解释器,它在操作系统的最外层,负责直接与用户对话,把用户的输入解释给操作系统,并处理各种各样的操作系统的输出结果,输出屏幕返回给用户。

这种对话方式可以是:

  1. 交互的方式:从键盘输入命令,通过/bin/bash的解释器,可以立即得到shell的回应
  2. 非交互的方式:脚本

Shell的英文意思是贝壳的意思,命令解释器Shell像一个贝壳一样包住系统核心。

Shell执行命令分为两种方式:

  • 内置命令:如讲过的cd,pwd,exit和echo等命令,当用户登录系统后,shell以及内置命令就被系统载入内存,并且一直运行。
  • 一般命令:如ls,磁盘上的程序文件-->调入-->执行命令

2.2 什么是shell脚本

当Linux命令或语句不在命令行下执行(严格说,命令行也是shell),而是通过一个程序文件执行时,该程序就被称为Shell脚本或Shell程序。

用户可以在Shell脚本中敲入一系列的命令及语句组合。

这些命令,变量和流程控制语句等有机的结合起来就形成一个功能强大的Shell脚本。

 

shell程序很类似DOS系统下的批处理程序(扩展名*.bat)。

2.3 一个简单的shell脚本

首先先带领大家写一个清空/var/log/messages日志的脚本

我们需要先想明白几个问题:

  1. 日志文件在哪?

    • /var/log/messages
  2. 用什么命令可以清空文件?
    • 重定向>
  3. 写一个简单的shell脚本。
 
  • 将所有命令放在一个文件里堆积起来就形成了脚本,下面就是一个最简单的命令堆积形成的shell脚本。
  • 要使用root身份来运行这个脚本
  • 清除日志脚本
[root@oldboy scripts]# cat clear_log_messages.sh
#!/bin/sh cd /var/log
cat /dev/null > messages
echo "Logs cleaned up."

上述脚本的问题:

  1. 如果不是root用户就无法执行清理日志
  2. 没有任何流程控制语句,简单的说,就是顺序操作,没有成功判断和逻辑严密性。
# 如果不是root用户,就无法修改日志文件/var/log/messages
[root@oldboy scripts]# ll /var/log/messages
-rw------- 1 root root 81192 Oct 15 15:24 /var/log/messages # 如果不是root用户就无法执行清理日志脚本
[root@oldboy scripts]# ls -l clear_log_messages.sh
-rw-r--r-- 1 root root 72 Oct 15 15:34 clear_log_messages.sh
  • 有没有脚本放在统一的目录下

    • /server/scripts
  • 授权:用那个用户执行文件
    • 需要对用户做判断
  • 清空错文件怎么办?
  • 错误提示:有没有成功?
  • 脚本的通用性

范例:包含命令,变量和流程控制的清空/var/log/messages日志的shell脚本

#!/bin/bash
# 清除日志脚本,版本2 LOG_DIR = /var/log
ROOT_UID = 0 # $UID 为0的时候,用户才具有root用户的权限 # 优雅提示:要使用root用户来运行
# $UID 系统变量,不需要定义
if ["$UID" -ne "$ROOT_UID"]
then
echo "Must be root to run this script."
exit 1 # 退出脚本,返回值1
fi cd $LOG_DIR || {
echo "Cannot change to necessary directory.">&2
exit 1
} cat /dev/null > messages && echo "Logs cleaned up."
exit 0 # 退出之前返回0 表示成功,返回1 表示失败。

编写shell的步骤:

  1. 必须是root才能执行脚本,否则退出
  2. 成功切换目录 cd /var/log,否则退出
  3. 清理日志 cat /dev/null > messages,清理成功,在输出
  4. 上述条件都确认ok,echo输出。
 

清空日志的三种方法:

  1. echo >test.log
  2. >test.log
  3. cat /dev/null > test.log

shell脚本在运维工作中的作用和地位:

shell脚本擅长处理文本类型的数据,而Linux中几乎所有的配置文件,日志文件等都是纯文本类型文件。 多数启动文件都是纯文本类型的文件。

因此,学好shell脚本语言,就可以利用它在linux系统中发挥巨大的作用。

 

运维的服务,通过shell管理和配置:

  • 基础命令
  • 定时任务
  • NFS服务
  • Rsync服务
  • ssh key服务
  • Nagios监控服务
  • Apache服务
  • MySQL服务
  • Php服务
  • Nginx服务
  • Lvs+keepalive服务
  • Cacti/Mrtg流量及监控
  • iptables防火墙

2.4 shell脚本语言的种类

在Unix和Linux中主要有两大类shell:

  • Bourne shell,包括sh,ksh,and bash

    • Bourne shell,sh,已经被bash取代
    • Korn shell,ksh
    • Bourne Again shell,bash
    • Posix shell,sh
  • C shell,包括csh和 tcsh
    • C shell,csh
    • TENEX/TOPS C shell, tcsh
 

shell脚本语言是弱类型语言

  • 较为通用的shell有标准的Bourne shell(sh)和C shell(csh)。
  • 其中Bourne shell(sh)已经被bash shell取代,
    • bourne Again shell(bash)是从sh发展而来的
    • bash和sh稍有不同,它还包含了csh和ksh的特色,但大多数脚本都可以不加修改地在bash上运行。
[root@oldboy scripts]# cat /etc/shells
/bin/sh # 最常用的
/bin/bash # 常用的,第二个的功能要比sh的功能更强
/sbin/nologin # 常用,
/bin/dash
/bin/tcsh
/bin/csh

其他语言:

  • php

    • php是网页程序,也是脚本语言。更专注于web页面开发,如:dedecms, discuz.
  • perl
    • perl脚本语言,比shell强大的多,语法灵活,复杂,实现方式很多,不易读,团队协作困难
  • python
    • 可以做脚本开发,也可以实现web开发。中等以上的公司都要求会python
 

shell脚本与php,perl,python语言的区别?

  • shell的优势在于处理操作系统底层的业务(大量的命令为它做支撑,2000多个命令都是shell支持,grep,awk,sed)
  • 一键安装,报警脚本,常规的业务应用,shell开发更简单快速。

  • php,python的优势在于开发运维工具,web界面的管理工具

 

常用操作系统的默认shell

  • linux 是 Bourne Again shell(bash)
  • solaris 是freeBSD 缺省的是 Bourne shell(sh)
  • AIX 下是 Korn Shell(ksh)
  • HP-UX 缺省的是POSIX shell(sh)

3. shell脚本的建立和执行

3.1 shell脚本的建立

shell脚本(bash shell程序)通常是在编辑器(如:vi/vim)中编写,由 Unix/Linux 命令、bash shell命令、程序结构控制语言和注释等内容组成。

 

3.1.1 脚本开头(第一行)

一个规范的shell脚本的第一行会指出由哪个程序(解释器)来执行脚本中的内容,在Linux bash办成中一般为:

#!/bin/bash

或
#!/bin/sh

查看服务脚本的开头:

[root@oldboy scripts]# head -1 /etc/init.d/mysqld
#!/bin/sh

#!

"#!" 又称为幻数,在执行bash脚本的时候,内核会根据它来确定该用哪个程序来解释脚本中的内容。

这一行必须在脚本顶端的第一行,如果不是第一行则为注释。

3.1.2 bash和sh的区别

[root@chensiqi1 scripts]# ll /bin/sh
lrwxrwxrwx. 1 root root 4 Dec 23 20:25 /bin/sh -> bash

sh是bash的软链接,推荐标准写法#!/bin/bash

 

不同语言脚本的开头写法

下面是linux中常用脚本语言开头的编码写法,不同语言脚本的开头一般都要加上如下相应语言的开头标识内容。

#!/bin/bash
#!/bin/sh
#!/usr/bin/awk
#!/bin/sed
#!/usr/bin/tcl
#!/usr/bin/expect
#!/usr/bin/perl
#!/usr/bin/env python

ash 是GNU/Linux 默认的shell,和Bourne shell(sh)兼容,Bash采用了Korn shell(ksh)和C Shell(csh)的特色。符合 IEEE POSIX P1003.2/ISO 9945.2 Shell and Tools 标准。

 

CentOS和RedHat Linux下默认的Shell 均为shell。

因此,在写shell脚本的时候,我们的脚本的开头也可以不加#!/bin/bash。

但如果当前的shell非你默认的shell时,比如tcsh,那么就必须要写#!。

否则脚本文件就只能执行一些命令的集合,不能够使用shell内建的指令。

所以,不管什么脚本最好都加上开头语言标识。

 

如果脚本的开头不指定解释器,那么,就要用对应的解释器来执行脚本。

例如:

  • bash test.sh
  • python test.py

下面是linux中启动文件的脚本的第一行的示例:

[root@oldboy scripts]# head -1 /etc/init.d/*
==> /etc/init.d/abrt-ccpp <==
#!/bin/bash ==> /etc/init.d/abrt-oops <==
#!/bin/bash ==> /etc/init.d/atd <==
#!/bin/sh ==> /etc/init.d/auditd <==
#!/bin/bash ==> /etc/init.d/blk-availability <==
#!/bin/bash ==> /etc/init.d/chktestd <==
# chkconfig:23456 66 33 ... ==> /etc/init.d/udev-post <==
#!/bin/bash

bash版本:

[root@oldboy /]# bash --version
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

bash漏洞【破壳漏洞】

如果是比较老的系统,需要注意shell的版本太低,有漏洞,需要升级shell

[root@chensiqi1 scripts]# yum -y update bash

#验证方法
[root@chensiqi1 scripts]# env x='(){ :;};echo be careful' bash -c "echo this is a test"
this is a test 如果返回2行
be careful
this is a test
这样的结果的话,请尽快升级。

3.1.3 脚本注释 "#"

在shell脚本中,跟在"#"后面的内容表示注释,用来对脚本进行注释说明。

 

3.2 shell脚本的执行

当shell脚本以非交互的方式运行时,它会先查找环境变量ENV,该变量指定了一个环境文件(通常是.bashrc),然后从该环境变量文件开始执行,当读取了ENV文件后,SHELL才开始执行shell脚本中的内容。

 

Shell脚本的执行通常可以采用以下三种方式:

  1. bash script-name 或 sh script-name(推荐使用)

    • 这种方法是当脚本本身没有可执行权限"x"时常使用的方法。
    • 或者文件开头没有指定解释器
  2. path/script-name 或 ./script-name (当前路径下执行脚本)
    • 这种方法首先需要给脚本文件可执行权限。

      • chmod +x script-name
  3. source script-name 或 . script-name 
    • source 或.在执行这个脚本的同时,可以将脚本中的函数和变量加载到当前Shell
    • 不会产生子shell
    • 又有点像nginx的include功能。
 

第三种方法通常是使用source 或"."点号读入或加载指定的shell脚本文件,然后,依次执行指定shell脚本文件 san.sh 中的所有语句。

这些语句将作为当前 父shell脚本 father.sh 进程的一部分运行。

因此,使用source 或者"."点号可以将 san.sh 自身脚本中的变量的值或函数等的返回值传递到当前的父shell脚本father.sh中使用。

这是第三种方法和前两种办法的最大区别。

 

source或者"."点号命令的功能:

  • 在当前shell中执行source或者"."点号,加载并执行相关脚本文件中的命令及语句
  • 而不是产生一个子shell来执行命令中的文件。
 

示例:

# 文件准备
[oldboy@oldboy scripts]$ cat test.sh
echo 'I am oldboy' # 使用第一种方法,指定解释器去执行shell脚本
[oldboy@oldboy scripts]$ sh test.sh
I am oldboy
[oldboy@oldboy scripts]$ bash test.sh
I am oldboy # 第二种方法,需要给文件添加执行权限后,才能成功执行
[oldboy@oldboy scripts]$ ./test.sh
-bash: ./test.sh: Permission denied
[oldboy@oldboy scripts]$ sudo chmod +x test.sh
[oldboy@oldboy scripts]$ ./test.sh
I am oldboy # 第三种方法:source和.
[oldboy@oldboy scripts]$ source test.sh
I am oldboy
[oldboy@oldboy scripts]$ . test.sh
I am oldboy

下面用示例说明source或 . 执行shell脚本文件和前两种执行方式的区别:

# 文件准备
[root@oldboy scripts]# echo 'userdir=`pwd`' >testsource.sh
[root@oldboy scripts]# cat testsource.sh
userdir=`pwd` # 第一种方法执行,执行echo $userdir 输出结果为空
[root@oldboy scripts]# sh testsource.sh
[root@oldboy scripts]# echo $userdir # 第三种方法执行,执行echo $userdir 输出结果为 /server/scripts
[root@oldboy scripts]# source testsource.sh
[root@oldboy scripts]# echo $userdir
/server/scripts

3.3 Shell脚本开发的规范和习惯

  1. 开头指定脚本解释器
  2. 开头加版本版权等信息,可配置~/.vimrc文件自动添加
  3. 脚本不要用中文注释,尽量用英文注释
  4. 脚本以.sh为扩展名
  5. 放在统一的目录
  6. 代码书写优秀习惯
    • 成对的内容一次性写出来,防止遗漏,如[],'',""等
    • []两端要有空格,先输入[]退格,输入2个空格,再退格写。
    • 流程控制语句一次书写完,再添加内容。
    • 通过缩进让代码易读
    • 脚本中的引号都是英文状态下的引号,其他字符也是英文状态。
 

1. 开头指定脚本解释器

[root@oldboy scripts]# head -1 /etc/init.d/mysqld
#!/bin/sh [root@oldboy scripts]# head -1 /etc/init.d/svnserve
#!/bin/bash

2. 开头加版本版权等信息,可配置~/.vimrc文件自动添加

可配置vim编辑文件时自动加上以上信息,方法是修改~/.vimrc配置文件

#!/bin/bash
# Date 2019-10-16
# Author: Created by Zoe
# Mail: 740466595@qq.com
# Func: This script is for MySQL backup
# V2.1

3. 脚本中不用中文注释,尽量用英文注释

4. 脚本以.sh扩展名

5. 放在统一的目录

6. 代码书写优秀习惯

  • 成对的内容一次性写出来,防止遗漏,如[],'',""等

    • (), [], '',"", ``
  • []两端要有空格,先输入[]退格,输入2个空格,再退格写。

    • [ contents ]
  • 流程控制语句一次书写完,再添加内容。
  • if 条件语句
    then
    内容
    fi
    for
    do
    内容
    done
  • 通过缩进让代码易读
  • 脚本中的引号都是英文状态下的引号,其他字符也是英文状态。

3.4 shell脚本开发制度及规范

【shell】shell脚本入门的更多相关文章

  1. Linux Shell脚本入门--cut命令

    Linux Shell脚本入门--cut命令 cut cut 命令可以从一个文本文件或者文本流中提取文本列. cut语法 [root@www ~]# cut -d'分隔字符' -f fields &l ...

  2. linux的shell脚本入门

    Linux shell脚本入门教程 为什么要进行shell编程 在Linux系统中,虽然有各种各样的图形化接口工具,但是sell仍然是一个非常灵活 的工具.Shell不仅仅是命令的收集,而且是一门非常 ...

  3. (一)shell脚本入门

    shell脚本入门 1.脚本格式 脚本以#!/bin/bash 开头(指定解析器) 2.第一个shell脚本:helloworld (1)需求:创建一个shell脚本,输出helloworld 运行: ...

  4. Linux Shell脚本入门--wget 命令用法详解

    Linux Shell脚本入门--wget 命令用法详解 wget是在Linux下开发的开放源代码的软件,作者是Hrvoje Niksic,后来被移植到包括Windows在内的各个平台上.它有以下功能 ...

  5. Shell脚本 (一) 概述、解析器、脚本入门

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 一. Shell 脚本概述 1. Shell 的 含义: Shell 是一个用C语言编写的程序,它是用户 ...

  6. SHELL (1) —— shell脚本入门

    摘自:Oldboy Linux运维——SHELL编程实战 SHELL Shell是一个命令解释器,解释执行用户输入的命令及程序等,用户每输入一条命令,Shell就解释执行一条.这种从键盘以输入命令,就 ...

  7. shell脚本 入门 —— 符号篇

    shell Shell就是一个命令行解释器,它的作用是解释执行用户的命令,用户输入一条命令,Shell就解释执行一条,这种方式称为交互式(Interactive). Shell还有一种执行命令的方式称 ...

  8. shell脚本入门笔记

    转载:http://mp.weixin.qq.com/s?__biz=MzA3MTIxNzkyNg==&mid=204081791&idx=1&sn=27bb1d827e0f8 ...

  9. 简单的 Shell 脚本入门教程

    Shell脚本 运作方式与解释型语言相当,如果有语言基础,学起 Shell 脚本就非常容易,但是 Shell 与常见的语言不同,一些常见的函数在 Shell 中需要组合一些命令得以实现 工具推荐 Sh ...

随机推荐

  1. fiddler详解

    一.介绍Fiddler是一个http协议调试工具,能记录并检查电脑和互联网之间的http通讯,设置断点,查看所有的“进出”fiddler的数据(cookie,html,js,css等文件) 通常可从以 ...

  2. 这可能是 Github 上最全面的 Flutter 教程

    引语 晚上好,我是猫咪,我的公众号「程序媛猫咪」会推荐 GitHub 上好玩的项目,挖掘开源的价值,欢迎关注我. 刚下班到家,金三银四,虽然今天行情尤其地不好,但身边的同事也是走了一波,不免会受到影响 ...

  3. String 对象-->概念和创建

    1.String 对象 String 对象用于处理文本(字符串). String 对象创建方法: new String(). 语法: var txt = new String("string ...

  4. python3(十七) nonameFunc

    L = list(map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9])) print(L) # [1, 4, 9, 16, 25, 36, 49, 64, ...

  5. Java成长第三集--基础重点详细说明

    接上篇文章,继续阐述相关的重点基础知识,话不多说! 一.Java中equals()和“==”区别 1.对于8种基础数据类型,使用“=="比较值是否相等: 2.对于复合数据类型(类),使用eq ...

  6. AJ学IOS 之微博项目实战(9)微博模型之时间相关重要操作,判断刚刚,昨天,今年等等

    AJ分享,必须精品 一:效果 二:实现代码 /** 1.今年 1> 今天 * 1分内: 刚刚 * 1分~59分内:xx分钟前 * 大于60分钟:xx小时前 2> 昨天 * 昨天 xx:xx ...

  7. Julia的基本知识

    知识来源 1.变量.整数和浮点数 Julia和Matllab挺像的,基本的变量,数值定义都差不多,所以就没必要记录了. 2.数学运算 3.函数

  8. L13过拟合欠拟合及其解决方案

    过拟合.欠拟合及其解决方案 过拟合.欠拟合的概念 权重衰减 丢弃法 模型选择.过拟合和欠拟合 训练误差和泛化误差 在解释上述现象之前,我们需要区分训练误差(training error)和泛化误差(g ...

  9. Equalizing by Division

    The only difference between easy and hard versions is the number of elements in the array. You are g ...

  10. redis: List列表类型(四)

    list设置值(头部):lpush list one list设置值(尾部):**rpush ** list one list获取值:lrange list 0 -1 list获取指定范围的值:lra ...