什么是Shell

解释Shell脚本名词之前,我们先来说下什么是Shell?

Shell是一个命令解释器,它在操作系统的最底层,负责直接与用户对话,把用户的输入解释给操作系统,并处理各种各样的操作系统的输出结果,输出到屏幕返回给用户。这种对话方式可以是交互的方式(从键盘输入命令,可以立即得到shell的回应),或非交互(脚本)的方式。

命令行解释器:使用户得以与内核进行沟通的“翻译官”

下面图中黄色部分就是命令解释器shell。

提示:Shell在英文中的意思是贝壳,从上图我们可以看出,命令解释器shell就像一个贝壳一样包住了系统核心。

解释:

用户下达指令,shell把用户的指令翻译成`系统内核`能识别的二进制数,然后传达给系统内核,系统内核会把指令进行查看分析,然后下达“进程调度”和“资源分配”指令给CPU,让CPU去执行,然后由计算机硬件来显示结果。

什么是shell脚本

Linux  Shell脚本 :实现某种功能的,有执行权限的文本文件

内核的作用:资源分配和进程调度

命令或语句不在命令行执行,而是通过一个程序文件执行时,该程序就被称为shell脚本或Shell程序,shell程序很类似DOS系统下的批处理程序(*.bat)。用户可以在shell脚本中敲入一系列的命令或命令语句。这些命令、变量和流程控制语句等有机的结合起来就形成了一个功能强大的shell脚本。

Windows下利用批处理程序bat开发的备份网站及数据库的脚本

@echo off
set date=%date:~,%-%date:~,%-%date:~,%
mysqldump -uroot -poldboy -A -B > D:\bak\"%date%".sql
rar.exe a -k -r -s -m1 D:\bak\"%date%".sql.rar D:\bak\"%date%".sql
del D:\bak\*.sql
rar.exe a -k -r -s -m1 D:\bak\"%date%"htdocs.rar D:\work\PHPnow\htdocs

范例1:清除.var/log下messages日志文件的简单命令脚本

#把所有命令放在一个文件里堆积起来就形成了脚本,下面就是一个最简单的命令堆积形成的shell脚本。

#必须使用root身份来运行这个脚本

#清除日志脚本,版本1

cd /var/log
cat /dev/null > messages
echo "Logs cleaned up."
#提示:/var/log/messages是系统的日志文件

看完这个脚本有什么想法?

)不是root执行不了

)没有流程控制,就是没有逻辑性

范例2:包含命令、变量和流程控制语句的清除/var/log下messages日志文件的shell脚本

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

扩展:

清除日志的三种方法:

[root@Web ~]# echo >test.log
[root@Web ~]# >test.log
[root@Web ~]# cat /dev/null >test.log

应用场景:保留文件,清空内容

脚本在执行时会启动一个子shell进程;

1.命令行中启动的脚本会继承当前shell环境变量;

2.系统自动执行的脚本(非命令行启动)就需要自我定义需要各环境变量;

编写脚本

1.指定脚本的执行环境  #!/bin/bash

2.注释信息

3.脚本的功能体

进程和shell的关系

1.在每个进程看来,当前主机上只存在内核和当前进程,不知道别的进程存在

2.进程是程序的副本,进程是程序执行实例

3.进程可同名,进程号不同就是不同的进程

4.进程是程序的副本,进程是程序执行示例

5.多个用户同时登录shell,每个Shell都会有所不同,彼此之间各不相干

6.允许同一个用户登录多次,每个Shell都会有所不同,彼此之间各不相干

7.同一个用户在不同地方登录的Shell都会不同,都对应不同的Shell进程
8.bash自身是一个外部程序,但启动以后会带有内部命令
9.父Shell的设定对于子Shell是无效的,所之亦然。
10.shell之间可以交互打开

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

Shell的优势在于处理操作系统底层的业务(大量的命令为它做支撑,例如,grep,sed,awk)。

一键安装,报警脚本,常规的业务应用,shell开发更简单快速。

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

Shell脚本很擅长处理纯文本类型的数据,而linux中几乎所有的配置文件、日志文件(如nfs,rsync,httpd,nginx,lvs等)都是纯文本类型的文本。因此,如果学好Shell脚本语言,就可以利用它Linux系统中发挥巨大的作用。

Linux系统支持的Shell

类型                说明
bsh:Bourne Shell     70年代中期诞生于贝尔实验室,脚本编程功能较强
csh             80年代早期诞生于加利福尼亚大学,使用C语言风格,命令行交互方便
ksh:Korn Shell     兼容Bsh的语法和C语法的交互特性
bash:Bourne-Again Shell bsh的升级版,吸取了ksh的一些特点,是大多数Linux的默认Shell程序 zsh             兼备各种Shell程序的优点,交互式操作效率更高

Shell脚本语言是弱类型语言,较为通用的shell有标准的Bourne shell (sh)和 C shell (csh)。其中 Bourne shell (sh)。其中 Bourne shell (sh)已经被bash shell取代。

当前的Linux主机支持哪些Shell?

#cat /etc/shells
/bin/sh //多数Unix默认的Shell
/bin/bash //多数Linux默认使用的Shell
/sbin/nologin //非登录Shell
/bin/tcsh
/bin/csh
/bin/csh
在RHEL系统中,实际上sh是bash的符号链接

CentOS Linux系统默认的shell是():

[root@Web ~]# echo $SHELL
/bin/bash
[root@Web ~]# grep root /etc/passwd
[root@Web ~]# grep root /etc/passwd
root:x:::root:/root:/bin/bash

Bash的基本特性

Tab键补全、快捷键
命令历史
命令别名
标准输入输出
重定向
管道操作

Tab键补全

命令补全    搜索PATH环境变量所指定的每个路径下以我们给出的字符串 开头的可执行文件,如果多于一个,两次tab,可以给出列表;否则将直接补全;
路径补全 搜索我们给出的起始路径下的每个文件名,并试图补全

快捷键

快捷键    注释
Ctrl+a 跳到命令行首
Ctrl+e 跳到命令行尾
Ctrl+u 删除光标至命令行首的内容
Ctrl+k 删除光标至命令行尾的内容
Ctrl+l 清屏

命令历史

默认记录1000条最近执行过的命令

存放位置:~/.bash_history

环境变量    注释
PATH   命令搜索路径
HISTSIZE 命令历史缓冲区大小

命令历史:history

参数选项    注释
-c 清空命令历史
-d OFFSET [n] 删除指定位置的命令
-w 保存命令历史至历史文件中

命令历史的使用技巧:

参数选项    注释
!n    执行命令历史中的第n条命令
!-n   执行命令历史中的倒数第n条命令;
!!    执行上一条命令;
!string 执行命令历史中最近一个以指定字符串开头的命令
!$    引用前一个命令的最后一个参数
Esc, .
Alt+.

命令别名

语法:

alias CMDALIAS='COMMAND [options] [arguments]'

有效范围

在shell中定义的别名仅在当前shell生命周期中有效
别名的有效范围 仅为当前shell进程

相关操作

相关操作                注释
aliase           列出已定义的命令别名
unaliase 别名        删除指定的命令别名
unaliase -a        清空所有别名
alias 别名='实际命令'   定义新的命令别名

如何让定义的别名命令生效?

vim  ~/.bashrc    只对某个用户生效
vim /etc/bashrc 对所有用户生效

标准输入输出

1.标准输入:从该设备接收用户输入的数据

2.标准输出:从该设备向用户输出的数据

3.标准错误:通过该设备报告执行中的出错信息

类型      设备文件      文件描述号    默认设备
标准输入 /dev/stdin         键盘
标准输出 /dev/stdout         显示器
标准错误 /dev/stderr        显示器

重定向

重定向:改变标准输入/输出/错误输出的方向

set -C    禁止对已经存在文件使用覆盖重定向
    强制覆盖输出,则使用 >|
set +C 关闭上述功能

类型

类型                    操作符          用途
重定向输入                <      将文本输入来源由键盘改为指定的文件
重定向输出                >     将命令行的正常执行输出保存到文件,而不是直接显示在屏幕上
                   >>     与>类似,但操作是追加而不是覆盖
重定向错误               >     将命令行的执行错误信息保存到文件,而不是直接显示在屏幕上
                   >> 与2>类似,但操作是追加而不是覆盖
混合重定向(重定向正确和错误输出信息) &>    相当于>和2>,覆盖到同一个文件
                   &>>   相当于>和2>>,追加到同一个文件

管道

管道:前一个命令的输出,作为后一个命令的输入

管道操作符”|“
cmd1 | cmd2 [...|cmdn] 将cmd1的输出结果,作为cmd2的输入

例如:

#pgrep -l "." | wc -l————统计运行的进程数
#ifconfig | grep "HWaddr"————查看本机的MAC地址信息

shell脚本的建立和执行

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

脚本开头(第一行)

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

#!/bin/bash

#!/bin/sh

“#!”又称为幻数,在执行bash脚本的时候,内核会根据它来确定该用哪个程序来解释脚本中的内容。这一行必须在脚本顶端的第一行,如果不是则为注释。

sh和bash的区别:

[root@Web ~]# ls -l /bin/sh
lrwxrwxrwx. root root 9月 /bin/sh -> bash
[root@Web ~]# ll /bin/sh
lrwxrwxrwx. root root 9月 /bin/sh -> bash

提示:sh为bash的软链接,这里推荐用标准写法#!/bin/bash

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

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

Centos和RedHat Linux下默认的Shell均为bash。因此,在写shell脚本的时候,我们的脚本的开头也可以不加#!/bin/bash。但如果当前的shell非你默认的shell时,比如tcsh,那么就必须要写#!了。否则脚本文件就只能执行命令的集合,不能够使用shell内建的指令了,建议读者养成习惯,不管什么脚本最好都加上开头语言标识。

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

bash test.sh
python test.py

脚本注释

在shell脚本中,跟在(#)井号后面的内容表示注释,用来对脚本进行注释说明,注释部分不会被当作程序执行,仅仅是给人看的,系统解释器看不到的,注释可自成一行,也可以跟在脚本命令后面与命令在同一行。开发脚步时,如果没有注释,其他人就很难理解脚本究竟在做什么,时间长了自己也会忘记。因此,我们要尽量养成对所做的工作(脚本等)书写注释的习惯,不光是方便别人,也方便自己,否则,写完一个脚本后也许几天后就记不起脚本的用途了,再重新阅读也会浪费很多宝贵时间。对于团队的协作也不利。

Shell脚本的执行

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

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

bash script-name 或sh script-name(推荐使用)
path/script-name或./script-name(当前路径下执行脚本)
source script-name或. script-name #注意”.”点号

执行说明:

1.第一种方法是当脚本文件本身没有可执行权限(即文件x位为-号)时常使用的方法,这里推荐使用bash执行,或者文件开头没有指定解释器(推荐的方法)

2.第二种方法需要先将脚本文件的权限改成可执行文件(即文件加x位),具体方法:chmod u+x script-name或chmod 755 script-name。

然后通过脚本路径就可以直接执行脚本了。

在生产环境中,不少读者在写完shell脚本后,由于疏忽忘记给予该脚本文件执行权限,就直接应用了,结果导致脚本没有按自己的意愿手动或定时执行。

避免的方法是用第一种方法替代第二种。

3.第三种方法是使用source或者”.”点号读入或加载指定的shell脚本文件(如san.sh),然后依次执行指定shell脚本文件san.sh中的所有语句。这些语句将作为当前父shell脚本father.sh进程的一部分运行。因此,使用source或者”.”点号可以将san.sh自身脚本中的变量的值或函数等的返回值传递到当前的父shell脚本father.sh中使用。这是第三种方法和前两种的最大区别。也是值得读者注意的地方。

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

下面我们举例说明

[zgy@Web ~]$ cat >test.sh                   #编辑test.sh脚本文件

echo 'I am zgy' echo 'I am zgy'  

输入"echo 'I am oldboy'"内容后按回车,然后在按ctrl+d组合键即可结束编辑。此操作作为特殊编辑方法,作为cat用法的扩展提及(在使用中去记忆是个好习惯)。

[zgy@Web ~]$ cat test.sh  

echo 'I am zgy'   

[zgy@Web ~]$ sh test.sh         #使用第一种方式的sh命令执行test.sh脚本文件

I am zgy

[zgy@Web ~]$ bash test.sh      #使用第一种方式的bash命令执行test.sh脚本命令

I am zgy

我们使用第一种方法,发现均可以执行并得到预期的结果。

zgy@Web ~]$ ls -l test.sh
-rw-rw-r--. zgy zgy 4月 : test.sh [zgy@Web ~]$ ./test.sh #使用第二种方式"./"在当前目录下执行test.sh脚本文件,可以发现,这个地方无法自动补全。
-bash: ./test.sh: 权限不够 #提示:此处没有可执行权限

但是可以用source或者"."点号执行。

[zgy@Web ~]$ . test.sh
I am zgy
[zgy@Web ~]$ source test.sh
I am zgy

提示:"."点号和source命令的功能相同,都是读入脚本并可以执行脚本

给test.sh加执行权限

[zgy@Web ~]$ chmod u+x test.sh
[zgy@Web ~]$ ./test.sh
I am zgy

可以看到,给test.sh加完可执行权限就可以执行了。

现在测试第三种source或者"."点号的特殊的传递变量值到当前shell的例子

[zgy@Web ~]$ echo 'userdir=`pwd`'>testsource.sh  #行的内容通常用echo很方便。
[zgy@Web ~]$ cat testsource.sh
userdir=`pwd`
[zgy@Web ~]$ sh testsource.sh
[zgy@Web ~]$ echo $userdir

#此处为空,并没有出现当前路径输出,这是为什么呢?

根据上面例子,可以发现,通过sh或bash命令执行过的脚本,脚本结束后在当前shell窗口查看userdir变量的值,发现变量值是空的。现在以同样的步骤改用source执行,然后再看看userdir变量的值

[zgy@Web ~]$ source testsource.sh
[zgy@Web ~]$ echo $userdir
/home/zgy

再看看系统Nfs服务的脚本如何使用”.”号的。

# Source function library.
. /etc/rc.d/init.d/functions

提示:操作系统及服务自带的脚本是学习的标杆和参考(虽然有时感觉不是很规范)

结论:

通过source或”.”点号加载执行过的脚本,在脚本结束后脚本中的变量值(包括函数)在当前Shell中依然存在,而是sh和bash则不行。

因此,在做Shell脚本开发时,如果脚本中有需求引用其他脚本的内容或者配置文件时,最好用”.”点号或source在脚本开头加载该脚本或配置文件,

然后再下面的内容用可以调用source加载的脚本及文件中的变量及函数等内容

某互联网公司Linux运维职位实际面试笔试

、已知如下命令返回结果,请问echo $user的返回的结果为()
[zgy@Web ~]$ cat test.sh
user=`whoami`
[zgy@Web ~]$ sh test.sh
[zgy@Web ~]$ echo $user
问:执行echo $user命令的结果是什么?
)当前用户
)zgy
)空(无内容输出) #这个是正确答案

Shell脚本开发基本规范及习惯

1)开头指定脚本解释器

#!/bin/sh或#!/bin/bash

2)开头加版权版本等信息

#Date: : --

#Author Created by zgy

#Mail @qq.com

#Function:  This scripts function is...

#Version 1.1

3)脚本中不用中文注释

尽量用英文注释,防止本机或切换系统环境后中文乱码的困扰

4)脚本以.sh为扩展名

例:script-name.sh

5)代码书写优秀习惯

1.成对内容的一次写出来,防止遗漏。如:

[]、{}、''、``、""

2.[]中括号两段要有空格,书写时即可留出空格[  ],然后在退格书写内容。

3.流程控制语句一次书写成,再添加内容,如:

if语句格式一次完成:

if  条件内容
then
内容
fi

for语句格式一次完成:

for
do
内容
done

提示:while和util,case等语句也是一样

6)通过缩进让代码易读

if 条件内容
then
内容
fi

提示:好的习惯可以避免很多不必要的麻烦,提升很多的工作效率。

最新文章

  1. MySQL 子分区
  2. U-boot中的FDT
  3. C#,往线程里传参数的方法总结
  4. 【转】Linux(Ubuntu)下面SecureCRT 完全破解
  5. Oracle 用户、对象权限、系统权限
  6. LINQ to SQL 增,删,改
  7. ELK日志检索并邮件微信通知
  8. 基于后端云的Android注册登录开发
  9. WindowsService调用API
  10. java面试一、1.4锁机制
  11. MHA环境搭建
  12. GCD on Blackboard
  13. 标准库 svc—程序及服务控制
  14. 双向链表--首页大小不一卡片排序 --- react --- js
  15. MySQL 5.6学习笔记(数据类型)
  16. 面试6 在c#中如何声明一个类不能被继承
  17. SSH整合报错:Unable to instantiate Action, testAction, defined for &#39;test&#39; in namespace &#39;/&#39;testAction
  18. CSS块级元素与行内元素
  19. MapReduce实战(六)共同粉丝
  20. Azure 11 月新公布

热门文章

  1. springBoot 集成redis客户端傻瓜式流程
  2. $Noip2013/Luogu1970$ 花匠 $dp$+思维
  3. Linux 文件系统 -- inode 笔记
  4. 还在使用OpenGL ES做渲染,你Out了,赶紧来拥抱Vulkan吧~
  5. Django 多表、跨表、聚合、分组查询
  6. BigInteger&amp;BigDecimal类
  7. Eclipse中安装Jetty服务器
  8. vue文字间歇无缝向上滚动
  9. 鉴于崔庆才大大的对于 beautifulsoup 的再理解
  10. Django2.0 配置 media