今天呢,我们主要学习shell编程!
-
首先,我们先了解下:用户是如何与计算机进行交互的?
-
答案是:终端+附着在终端上的用户接口程序。
用户接口程序主要有两类:GUI 和 CLI
-
GUI :图形化界面,例如 KDE , GNOME , Xfce
-
CLI : 命令行界面,例如 /etc/shells 包括 bash zsh 和 fish
之前呢,我们已经了解过bash的9大特性了,我们补充一点关于bash特性的内容。
bash基础特性9:命令Hash
**命令hash **
bash会缓存已经执行过的外部命令的完整路径,以及命令执行次数,称为命中(hit)次数。
数据格式为:key-value ,其中,key为搜索键,value为值。
hash : 查看hash列表
用法:
# hash
直接使用会列出hash列表
# hash -d COMMAND
从hash表中删除指定命令
# hash -r
清空hash表
示例:
[root@localhost jeffrey]# hash
hits command
6 /bin/mktemp
2 /bin/whoami
2 /bin/ls
[root@localhost jeffrey]# hash -d ls
[root@localhost jeffrey]# hash
hits command
6 /bin/mktemp
2 /bin/whoami
[root@localhost jeffrey]# hash -r
[root@localhost jeffrey]# hash
hash: hash table empty
bash基础特性10:变量
首先,叙述一下一些基础知识:
- 程序=指令+数据
而指令一般都是程序文件中写好的,数据则由“I/O设备,文件,管道和变量”提供。
- 编程语言类型
编程语言从变量类型上可分为两类:强类型变量编程语言和弱类型变量编程语言。
强类型变量是指变量有非常明显和严格的类型规范和要求;如C语言
弱类型变量是指变量要求没有严格要求,默认情况下均为同一种类型;如bash
接下来,我们来研究一下bash中的变量。
bash中的变量特点如下:
1,bash把所有变量统统视作字符型;
2,bash中的变量无需事先声明,声明与赋值同时完成;声明的是:变量类型和变量名。
3,变量替换:把变量名出现的位置,替换为其所指向的内存空间中的值;
4,变量引用:
- $ (var_name)
- $ var_name
5,变量命名
-
命名规则:变量名为字母、数字、下划线的任意组合,但是不能以数字开头,且不能使用关键字;
-
命名要求:见名知义,命名机制遵循某种法则;
6,bash变量类型
-
本地变量:作用域为当前shell进程;
-
环境变量:作用域为当前进程及其子进程;
-
局部变量:作用域为某个代码片段;
-
位置参数变量:向执行脚本的shell进程传递的参数;
-
特殊变量:shell内置的有特殊功能的变量;如 $? 保存命令执行的状态结果;
下面我们对以上变量进行详细的介绍:
本地变量:
1,赋值
name=value
2,引用
${name}
$name
" " : 双引号,变量名替换为其值;
‘ ’ :单引号,变量名不替换为其值;
3,查看变量列表
# set
4,撤销变量
# unset name
撤销指定变量
我们设计步骤来证明:本地变量作用域对子进程无效:
//首先在当前shell下创建本地变量myname=jeffrey
[root@localhost jeffrey]# myname=jeffrey
//引用一下以验证本地变量myname的值
[root@localhost jeffrey]# echo $myname
jeffrey
//然后,我们打开子shell进程
[root@localhost jeffrey]# bash
//在子进程里,引用变量myname,发现并没有值,说明在子进程中失效;
[root@localhost jeffrey]# echo $myname
环境变量
bash内嵌了许多环境变量(通常全为大写字母),用于定义bash的工作环境;
如:
PATH HISTSIZE HISTFILE HISTFILESIZE HISTCONTROL SHELL HOME UID PWD OLDPWD
1,赋值
方法1:
# export name=value
方法2:
# name=value
# export name
方法3:
# declare -x name=value
方法4:
# name=value
# declare -x name
2,引用
$ {name}
$ name
3,显示环境变量
以下四种均可:
# export
# declare -x
# printenv
# env
4,撤销环境变量
# unset name
5,定义只读变量
方法1
# declare -r name
方法2
# readonly name
只读变量无法重新赋值,并且不能撤销,存活时间为当前shell进程,随shell进程的终止而终止。
bash基础特性11:多命令执行
用法:
# COMMAND1 ; COMMAND2 ; COMMAND3 ;…
逻辑运算:
运算数为:
- 真(true yes on 1)
- 假(false no off 0)
运算类型为:
- 与(&&)
1&&1=1
1&&0=0
0&&0=0
0&&1=0
- 或(| |)
1| |1=1
1| |0=1
0| |0=0
0| |1=1
- 非( !)
! 1 = 0
! 0 = 1
短路法则:
# COMMAND1 && COMMAND2
若COMMAND1执行成功,即为真,则COMMAND2必须执行;
若COMMAND1执行失败,即为假,则COMMAND2不会执行;
# COMMAND1 | | COMMAND2
若COMMAND1执行成功,即为真,则COMMAND2不会执行;
若COMMAND1执行失败,即为假,则COMMAND2必须执行;
示例:
[root@localhost jeffrey]# id user
id: user: no such user
[root@localhost jeffrey]# id user || useradd user
id: user: no such user
[root@localhost jeffrey]# id user
uid=1003(user) gid=1004(user) groups=1004(user)
说了这么多,下面正式进入shell脚本编程的环节!
我们先来从不同角度讨论一下编程语言的类型。
1,编程语言分类
- 根据运行方式:分为 编译运行 和 解释运行
编译运行:编写源代码 —> 编译器编译 —> 可执行程序文件
解释运行:编写源代码 —> 运行时启动解释器,由解释器边解释边运行
- 根据编程过程中功能的实现是调用库还是外部文件:分为 shell脚本编程 和 完整编程
shell脚本编程:利用系统命令及编程组件进行编程
完整编程:利用库或编程组件进行编程
- 根据编程摸型(程序=指令+数据):分为 过程式编程语言 和 面向对象的编程语言
过程式编程语言:以指令为中心来组织代码,数据服务于代码;如:C语言,bash
面向对象的编程语言:以数据为中心来组织代码,围绕数据来组织指令;如:Java,C++,Python
shell脚本编程
1,什么是shell脚本编程?
shell脚本编程是一种过程式编程,边解释边运行,依赖于外部程序文件执行;
2,如何编写shell脚本?
因为shell脚本本身就是一个文件,所以直接用文本编辑器编写即可,文本编辑器有两种:行编辑器和全屏编辑器。所谓行编辑器,就是一次编辑一行,而全屏编辑器就是打开后整个界面完全进入编辑状态,比如 nano 和 vim.
-
脚本文件第一行,顶格,给出shebang,即解释器路径,用于指明解释执行当前脚本的解释器程序文件;
>常见的解释器
#!/bin/bash
#!/usr/bin/python
#!/usr/bin/perl
-
shell脚本中以#作为注释符;#后面的内容会被当做注释
-
shell脚本中的空白行会被解释器忽略;
3,shell脚本中的注意事项
shell脚本是命令的堆积;由于许多命令不具有幂等性(幂等性:重复执行命令时返回相同或相似结果),因此要加入判断语句,以避免发生错误。
示例:
//首先我们编写一个脚本,命名为myfirst.sh
//脚本功能为“若用户user不存在,则创建用户user,并修改其密码为"user":内容如下:
#!/bin/bash
#
useradd user
echo "user" | passwd --stdin user
/接下来,我们来实验一下,id user发现之前不存在用户usr
[root@localhost jeffrey]# id user
id: user: no such user
//然后我们执行脚本(脚本执行方式下面会介绍),根据提示信息可知,密码已修改。
[root@localhost jeffrey]# bash myfirst.sh
Changing password for user user.
passwd: all authentication tokens updated successfully.
//接下来,我们测试一下user是否创建成功,结果显示了user的id信息,说明user已经建立;
[root@localhost jeffrey]# id user
uid=1003(user) gid=1004(user) groups=1004(user)
//此时,我们再次执行脚本,看看会有什么情况发生?
[root@localhost jeffrey]# bash mufirst.sh
bash: mufirst.sh: No such file or directory
//结果显示,用户user已经存在,所以,脚本中的useradd命令执行结果是失败的
//提示密码已修改成功,说名命令passwd的执行是成功的。
//像useradd这种多次执行会报错的,就是不具有幂等性的命令
[root@localhost jeffrey]# bash myfirst.sh
useradd: user 'user' already exists
Changing password for user user.
passwd: all authentication tokens updated successfully.
4,脚本的运行方式
我们需要知道的一点是:脚本实在子shell进程中执行的;
方法1:
赋予脚本文件的执行权限,并直接运行此程序文件
chmod +x myfirst.sh
./myfirst.sh
方法2:
将脚本文件以命令行参数传递给解释器程序
bash myfirst.sh
好吧,光说不练假把式,我们来做个练习吧!
练习:编写脚本已完成下列功能:
- 找出/etc目录下,以大写或小写p开头的文件或目录
- 将/var目录下的所有文件名转换为大写后输出的屏幕上
示例:
#!/bin/bash
#
echo "完成功能1:"
ls -d /etc/[pP]*
echo
echo "完成功能2:"
ls -d /var/* | tr a-z A-Z
echo
执行结果:
[root@localhost jeffrey]# bash myfirst.sh
完成功能1:
/etc/PackageKit /etc/pinforc /etc/pnm2ppa.conf /etc/prelink.conf.d /etc/pulse
/etc/pam.d /etc/pkcs11 /etc/polkit-1 /etc/printcap /etc/purple
/etc/passwd /etc/pki /etc/popt.d /etc/profile /etc/python
/etc/passwd- /etc/plymouth /etc/postfix /etc/profile.d
/etc/pbm2ppa.conf /etc/pm /etc/ppp /etc/protocols
完成功能2:
/VAR/ACCOUNT
/VAR/ADM
/VAR/CACHE
/VAR/CRASH
/VAR/DB
/VAR/EMPTY
/VAR/GAMES
/VAR/GOPHER
/VAR/KERBEROS
/VAR/LIB
/VAR/LOCAL
/VAR/LOCK
/VAR/LOG
/VAR/MAIL
/VAR/NIS
/VAR/OPT
/VAR/PRESERVE
/VAR/RUN
/VAR/SPOOL
/VAR/TARGET
/VAR/TMP
/VAR/Y
bash配置文件
在介绍bash的各个配置文件之前,我们先认识一下:shell登录的类型
shell登陆类型可分为以下两种:
- 交互式登录shell进程
直接通过某终端输入账号和密码后,登录打开的shell进程;
或者使用su - username 或者使用su -l username 执行的登录切换;
- 非交互式登录shell进程
su username 执行的登录切换;
图形界面下打开的终端;
运行脚本;
了解了shell登录类型,我们就开始介绍bash的配置文件:
bash配置文件可分为以下两种:
- profile类
为交互式登录的shell进程提供配置
- bashrc类
为非交互式登录的shell进程提供配置
接着,我们再详细介绍一下这两种bash配置文件。
profile类配置文件
包括全局配置:对所有用户都有效;
/etc / profile
/etc / profile.d / *.sh
用户个人配置:支队当前用户有效;
~ / .bash_profile
profile类配置文件功能:一是用于定义环境变量,二是运行命令或脚本
bashrc类配置文件
包括全局配置:对所有用户都有效;
/ etc / bashrc
用户个人配置:支队当前用户有效;
~ / . bashrc
bashrc类配置文件功能:一是定义本地变量,二是定义命令别名;
注意,只有管理员才有权限修改全局配置文件。
交互式登录的shell进程读取配置文件顺序
/ etc /profile —> / etc / profile . d / * —> ~ / . bash_profile —> ~ / . bashrc —> / etc / bashrc
非交互式登录shell进程,读取配置文件顺序
~/.bashrc —> /etc/bashrc —> /etc/profile.d/*.sh
bash配置文件特性
命令行中定义的配置特性,如变量和命令别名,作用域为当前shell进程;
bash配置文件中定义的配置特性:只对随后新启动的shell进程有效;
那么,问题来了,如何让配置文件中定义的特性立即生效呢?
如何让配置文件中特性立即生效?
方法1:
通过命令行重新定义一次
方法2:
让当前shell进程重读配置文件
方法1:
# source CONF_FILE
方法2:
#.CONF_FILE
下面我们来示例说明:
在.bashrc配置文件中给命令ls设置别名为list
[root@localhost ~]# cat .bashrc
# .bashrc
# User specific aliases and functions
alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'
alias list='ls'
# Source global definitions
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi
[root@localhost ~]# list
bash: list: command not found...
[root@localhost ~]# source .bashrc
[root@localhost ~]# list
a_c b_c Documents Music Public
a_d b_d Downloads original-ks.cfg Templates
anaconda-ks.cfg Desktop initial-setup-ks.cfg Pictures Videos