走进shell
什么是shell
shell的作用是:
- 解释执行用户输入的命令或程序等
- 用户输入一条命令,shell就解释一条
- 键盘输入命令,Linux给与响应的方式,称之为交互式式
shell是一块包裹这系统核心的壳,处于操作系统的最外层,与用户直接对话,把用户的输入,解释给操作系统,然后处理操作系统的输出结果,输出到屏幕给与用户看到结果
从我们登入Linux,输入账号密码到进去Linux交互式界面,所有的操作都是交给shell解释并执行
shell运行的一个流程
我们想要获取计算就的数据,不可能每次都编写程序,编译后,再运行,再得到我们想要的,例如你想找到一个文件,可以先写一段c语言的代码。然后调用系统函数,通过gcc编译后,运行程序才能找到文件。。。
因此有大牛开发出了shell解释器,能够让我们方便的使用Linux,例如只要敲下ls -l这样的字符串,shell解释器就会针对这句话翻译,解释成ls -l -h 然后执行,通过终端输出结果,无论是图形化还是命令行界面
即使我们用的图形化,点点点的动作,区别也只是
- 命令行操作,shell解释执行后,输出结果到黑屏命令行界面
- 图形化操作,shell接受点击动作,输出图案数据
shell和运维
shell脚本语言很适合处理纯文本类型数据,且Linux的哲学思想就是一切皆文件,如日志丶配置文件丶文本丶网页文件丶,大多数都是纯文本类型的,因此shell可以进行方便的文本处理,好比强大的Linux三剑客(awk sed grep )
什么是shell脚本
当命令或者程序语句写在文件中,我们执行文件,读取其中的代码,这个程序文件就称之为shell脚本
在sehll脚本里重定义多条Linux命令以及循环控制语句,然后将这些Linux命令一次性执行完毕,执行脚本文件的方式称之为,非交互式方式
- windowsh中存在*.bat 批处理脚本
- LInux中常用*.sh 脚本文件
shell脚本规则:shell脚本或者称之为(bash shell程序)通常都是vim编辑,由Linux命令丶bash shell指令丶 逻辑控制语句和注释信息组成
shell语言定义的变量,数据类型默认都是字符串类型
int 数字数据类型
shebang
计算机程序中,shabang指的是出现在文本文件的第一行两个字符#!
在Unix系统中,程序会分析shabang后面的内容,作为解释器的命令,例如:
- 以#!/bin/sh开头的文件,程序在执行的时候会调用/bin/sh,也就是 bash解释器
- 以#!/usr/bin/python开头的文件,代表指定python解释器取执行
- 以#!/usr/bin/env [解释器名称],是一种在不同平台上都能正确找到解释器的办法
注意:
- 如果脚本未指定shabang,脚本执行的时候,默认用当前shell去解释脚本,既$SHELL
- 如果shabang指定了可执行的解释器,如 /bin/bash /usr/bin/python ,脚本在执行时,文件名会作为参数传递给解释器
- 如果#!指定的解释器没有可执行权限,则会报错“bad inteerpreter:Permission denied”
- 如果#!指定的解释程序不是一个可执行文件,那么指定的解释程序会被忽略,转而交给当前的SHELL去执行这个脚本
- 如果#!指定的解释程序不存在,那么会报错“bad inteerpreter:No such file or direc'tory”
- #!之后的解释程序,需要写绝对路径(如#!/bin/bash),它是不会自动到$PATH中寻找解释器的
- 如果你使用“bash test.sh”这样的命令来执行脚本,那么#!这一行将会被忽略掉,解释器当然是用命令行中显示指定的bash。
脚本案列:
脚本注释,脚本开发规范
- 在shell脚本中,#后面的内容代表注释掉的内容,提供给开发者和使用者观看,系统就会忽略这行
- 注释可以单独写一行,也可以跟在命令后面
- 尽量保持爱写注释的习惯,便于以后回顾代码的含义,尽量使用英文而非中文
执行shell脚本的方式
- bash scripts.sh或sh scripts.sh,文件本身没执行权限,没x权限则使用的方法,或脚本未指定shabang,重点推荐的方式
- 使用绝对/相对路径执行脚本,需要文件含义x权限
- source scripts.sh或者. scripts.sh,代表执行的含义,source等于.(点)
- 少见的用法,sh < scripts.sh
脚本语言
shell脚本语言属于一种弱类型语言,无需声明变量类型,直接定义使用
强类型语言,必须定义变量类型,确定是数字丶字符串等。之后在赋予同类型的值
centos7系统中支持的shell情况,有如下种类:
默认的sh解释器
其他脚本语言
- PHP是网页程序语言,专注于web页面开发,诸多开源产品,wordpress丶discuz开源产品都是PHP开发
- perl语言,擅长支持强大的正则表达式,以及运维工具开发
- Python语言,明星语言,不仅适用于脚本程序开发,如(系统后台,资产管理平台),爬虫程序开发,大量Linux运维工具也有Python开发,甚至于游戏开发使用
shell的优势
虽然有诸多的脚本编程语言,但是对于Linux操作系统内部应用而言,shell是最好的工具,Linux底层命令都支持shell语句,以及结合三剑客(awk sed grep )进行高级用法
- 擅长系统管理脚本开发,如软件启停脚本丶监控报警脚本丶日志分析脚本,每个语言都有自己擅长的地方,扬长避短,达到高效运维的目的是最合适的
bash基础特性
bash是什么
- bash是一个命令处理器,运行在文本窗口中,并能执行用户直接输入的命令
- bash还能从文件中读取linux命令,称之为脚本
- bash支持通配符丶管道丶命令替换丶条件判断等逻辑控制语句
bash有诸多方便的功能,有助于运维人员提升工作效率
命令历史
shell会保留其会话中用户提交执行的命令
bash特性汇总
- 文件路径tab键补全
- 命令补全
- 快捷键ctrl+a,e,u,k,l
- 通配符
- 命令历史
- 命令别名
- 命令行展开
变量含义
学生时代所学的数学方程式,如x=1,y=2,那会称之为x,y为未知数
对于计算就而已,x=1,y=2等于定义了两个变量,名字分别是x,y。且赋值了1和2
**变量是暂时存储数据的地方,是一种数据标记(房间号,标记了客人所在的位置),数据存储在内容空间,通过调用正确的变量名字,即可取出对应的值。
shell的变量
- 变量定义与赋值,注意变量与值之间不得有空格
- 变量替换/引用
- 变量名规则
- 名称定义要做到见明知意,且按照规则来,切不得引用保留关键字(help检查保留字)
- 只能包含数字丶字母丶下划线
- 不能以数字开头i
- 不能用标点符号
- 变量名严格区分大小写
- 变量的作用域
- 本地变量,只针对当前的sehll进程
父,子shell的不同作用域:
pstree检查进程树
- 本地变量,当前的shell
单引号变量,不识别特殊语法
双引号变量,识别特殊语法
- 环境变量,也称全局变量,针对当前shell以及其任意子进程,环境变量也分自定义丶内置两种环境变量
- 局部变量,针对在shell函数或是shell脚本中定义
- 位置参数变量:用于shell脚本中传递的参数
- 特殊变量:shell内置的特殊功效变量
- $?
- 0:成功
- 1-255:错误码
- 自定义变量
- 变量赋值:varName=value
- 变量引用: ${varName} 丶$varName
- 双引号,变量名会替换为变量值
- 单引号,识别为普通字符串
不同的执行方式,不同的shell环境
不同环境的区别:
#注意 :
每次调用bash/sh都会开启一个子shell,因此不保留当前的shell变量,通过pstree命令查看进程树
调用source实在当前shell环境加载变量,因此保留变量
shell变量面试题
问,如下输出什么内容
#注:
`linux命令`
在linux中反引号中的命令执行结果会被保留下来
例:
答:c
因为whoami加的是反引号,所以输出结果应是root
但是,因为是用sh运行的脚本,开启了一个子shell
所以echo输出结果为空
如果,用source运行,则输出root
环境变量设置
环境变量一般指的是用export内置命令导出的变量,用于定义shell的运行环境,保证shell命令的正确执行。shell通过环境变量确定登录的用户名丶PATH路径丶文件系统等各种应用
环境变量可以在命令行中临时创建,但是用户退出shell终端,变量即丢失,如要永久生效,需要修改环境变量设置
用户个人配置文件**~/.bash_profile丶~/.bashrc**远程登录用户特有文件
全局配置文件**/etc/profile丶/etc/bashrc,**且系统建议最好创键在**/etc/profile.d/,**而非直接修改主文件,修改全局配置文件,影响所以登录的用户
检查系统环境变量的命令:
set:输出所有变量,包括全局变量丶局部变量(指sh脚本文件中定义的变量)
env:只显示全局变量
declare:输出所有变量,如同‘set’
export:显示和设置环境变量值
撤销环境变量:
语法:unset 变量名,删除变量名或函数
设置只读变量:
- readonly,只有shell结束,只读变量失效
[root@hadoop102 ~]# readonly name=jiujiu
[root@hadoop102 ~]# echo $name
jiujiu
[root@hadoop102 ~]# name=like
-bash: name: readonly variable
[root@hadoop102 ~]# unset name
-bash: unset: name: cannot unset: readonly variable
试题:
过滤出,格式化所有的linux环境变量
[root@hadoop102 ~]# export | awk -F '[ =]' '{print $3}'
HISTCONTROL
HISTSIZE
HOME
HOSTNAME
LANG
LESSOPEN
LOGNAME
LS_COLORS
MAIL
OLDPWD
PATH
PWD
SELINUX_LEVEL_REQUESTED
SELINUX_ROLE_REQUESTED
SELINUX_USE_CURRENT_RANGE
SHELL
SHLVL
SSH_CLIENT
SSH_CONNECTION
SSH_TTY
TERM
USER
XDG_RUNTIME_DIR
XDG_SESSION_ID
bash多命令执行
[root@hadoop102 ~]# ll jiujiu/;ll dir1/;cd jiujiu
total 0
-rw-r--r--. 1 root root 0 Mar 28 11:43 like
total 0
-rw-r--r--. 1 root root 0 Mar 27 18:14 file1
-rw-r--r--. 1 root root 0 Mar 27 18:14 file10
-rw-r--r--. 1 root root 0 Mar 27 18:14 file2
-rw-r--r--. 1 root root 0 Mar 27 18:14 file3
-rw-r--r--. 1 root root 0 Mar 27 18:14 file4
-rw-r--r--. 1 root root 0 Mar 27 18:14 file5
-rw-r--r--. 1 root root 0 Mar 27 18:14 file6
-rw-r--r--. 1 root root 0 Mar 27 18:14 file7
-rw-r--r--. 1 root root 0 Mar 27 18:14 file8
-rw-r--r--. 1 root root 0 Mar 27 18:14 file9
[root@hadoop102 jiujiu]#
#命令之间用分号相隔
环境变量初始化与加载顺序
shell变量
本地变量
- 定义shell变量,变量名不需要加美元符$
- 本地变量只在用户当前shell生存期中生效,如:
[root@hadoop102 ~]# name="jiujiu"
[root@hadoop102 ~]# echo $name
jiujiu
[root@hadoop102 ~]# bash (开启子shell)
[root@hadoop102 ~]# echo $name
[root@hadoop102 ~]# exit
exit
[root@hadoop102 ~]# echo $name
jiujiu
[root@hadoop102 ~]#
变量定义
变量名要求:字母丶数字丶下划线组成,可以是字母或是下划线开头,如:
- jiujiu
- jiujiu_123
- _jiujiu123
变量名严格区分大小写:
- jiujiu_123
- Jiujiu_123
#变量名的大小写会影响到想要的的变量结果
-
1.赋值不加引号
-
[root@hadoop102 ~]# name=jiujiu
-
2.赋值加单引号
-
[root@hadoop102 ~]# name='jiujiu'
-
-
3.赋值加双引号
-
[root@hadoop102 ~]# name="jiujiu"
-
取出变量值
- 单引号:所见即所得,强引用
- 双引号:输出引号里所有内容,识别特殊符号,弱引用
- 无引号:连续的符号可以不加引号,有空格则有歧义,最好使用双引号
- 反引号:引用命令执行结果,等于$()用法
特殊变量
shell的特殊变量,用在如脚本,函数传递参数调用,有如下特殊的,位置参数变量
$0 :获取shell脚本文件名,以及脚本路径
$n :获取shell脚本的第n个参数,n在1~9之间,如$1,$2..$9. 大于9则需要写成${10},参数空格隔开
$# :获取执行的shell脚本后面的参数总个数
$* :获取shell脚本所有参数,不加引号等同于$@的作用,加上引号“$*”的作用是 接收所有参数为单个字符,如“$1 $2.....”
$@ :不加引号,效果同上,加引号,是接收所有参数为独立字符串,如“$1” “$2” “$3” ...,空格保留
脚本实践:
[root@hadoop102 ~]# vim like.sh
[root@hadoop102 ~]# bash like.sh jiujiu 185 120 200 500
like.sh: line 1: !#/bin/bash: No such file or directory
特殊变量$0 $1 $2 ..的实践
结果: like.sh jiujiu 185
-------------------------------
特殊变量$#获取参数总个数
‘结果: ’ 5
--------------------------------
特殊变量$* 实践
结果: jiujiu 185 120 200 500
---------------------------
特殊变量$@ 实践
结果: jiujiu 185 120 200 500
面试题例:
问:$*和$@的区别你了解吗?
答:
$*和$@都表示传递给函数或脚本的所有参数
当$*和$@不被双引号" "包围时,它们之间没有任何区别,都是将接收到的每一个参数看做一份数据,彼此之间以空格分割
但是当它们被双引号" "包含时,就会有区别了:
"$*"会将所有的参数从整体上看做一份数据,而不是把每个参数都看作数据
"$@"仍然将每个参数都看作一份数据,彼此之间是独立的
比如传递了5个参数,那么对于"$*"来说,这5个参数会合并到一起形成一份数据,它们之间是无法分割的;而对于"$@"来说,这5个参数是相互独立的,它们是5份数据
如果使用echo直接输出"$*"和"$@"做对比,是看不区别的;但如果使用for循环来逐个输出数据,立即就能看出区别来
实践区别:
[root@hadoop102 ~]# vim jiujiu.sh
[root@hadoop102 ~]# cat jiujiu.sh
!#/bin/bash
echo "print each param from \"\$*\""
for var in "$*"
do
echo "$var"
done
echo "print each param from \"\$@\""
for var in "$@"
do
echo "$var"
done
[root@hadoop102 ~]# bash jiujiu.sh like 185 120 500
jiujiu.sh: line 1: !#/bin/bash: No such file or directory
print each param from "$*"
like 185 120 500
print each param from "$@"
like
185
120
500