文章目录
一、shell
Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。
Shell是系统的用户界面,提供了用户和内核进行互操作的一种接口。它接受用户的输入,并将命令传送到内核中去执行
Linux(以及Unix或类Unix)中的Shell有多种类型,其中最常用的种类有Bourne Shell(sh)、C Shell和Korn Shell。还包括了一些其他的Shell类型,如比较流行的ash和zsh等;但无论哪一种Shell,它最主要的功用都是解译使用者在命令行提示符中输入的指令。
查看系统中所有可用的Shell:
cat /etc/shells
查看系统的默认shell:
echo $SHELL
Shell 既是一种命令语言,又是一种程序设计语言。shell编程就是对一堆Linux命令的逻辑化处理
一个系统可以存在多个shell,不同的shell可能支持的命令语法是不相同的
二、shell脚本
Shell 脚本(shell script),是一种为 shell 编写的脚本程序。
脚本: 本质是一个文件,文件里面存放的是 特定格式的指令,系统可以使用脚本解析器翻译或解析指令并执行(它不需要编译)
shell脚本是一种脚本语言,我们只需使用任意文本编辑器,按照语法进行编写,增加可执行权限,即可在安装shell命令解释器的环境下执行
Linux 中通常使用功能强大的 vim 编辑器来编写。同时也可以对用户vim配置文件(即用户家目录下的.vimrc文件)根据shell语法等进行相应配置,以使编写shell脚本更加高效,便捷
(一)shell脚本书写规范:
- 首行:表示脚本将要调用的shell解释器
#!/bin/bash #具体以系统的shell解释器为准
#!符号能够被内核识别成是一个脚本的开始,这一行必须位于脚本的首行,/bin/bash是bash程序的绝对路径,在这里表示后续的内容将通过bash程序解释执行。
如果脚本的开头不指定解释器,那么脚本就会使用系统默认的解释器执行,这样在某些情况下就会出现错误
-
首行下以注释方式添加时间、作者、联系邮箱、脚本作用、版权等信息
可配置vim编辑文件时自动加上以上信息,方法是修改~/.vimrc配置文件
-
代码有注释
注释的意义不仅在于解释用途,而在于告诉我们注意事项,就像是README;脚本中尽量不要使用中文注释,防止切换系统环境后出现中文乱码问题;如果非要加中文建议脚本中添加: export LANG="zh_CN.UTF-8
单行注释:
# 注释内容
块注释:
:<<BLOCK
……
注释内容
……
BLOCK
-
命名要规范
1.文件名规范,以.sh结尾,方便识别;
2.通过脚本名称最好能够直接读出脚本的用途;
3.变量名必须是以字母或下划线”_”开头,后面跟字母、数字或下划线;
4.变量名字要有含义,尽量使用英文,常量大写
5.变量名中间不能有空格,可以使用下划线连接
6.统一命名风格,用驼峰或者下划线连接(小写字母加下划线的方式)
7.自定义变量尽量不要和系统环境变量冲突。
-
代码有缩进
良好的缩进可以大幅提高代码阅读性
-
代码太长要分行
参数可能会很长,这时候为了保证较好的阅读体验,可以用空格加反斜杠进行分行
-
成对的符号应该一次写完,然后退格在括号增加内容。如[ ]、{ }、“ ”、``、‘ ’、等等
-
流程控制语句应该先写将格式写完,再添加内容,避免嵌套增多时遗漏
-
代码要简短
不仅是指代码长度,还包括用到的命令。原则上能一条命令解决的问题绝不用多条。这不仅牵涉到代码的可读性,而且也关乎代码的执行效率。(避免使用管道和cat命令、外部命令等,内部命令执行效率大于外部命令)
(二)shell脚本的执行
当Shell脚本运行时会先查找env,该变量指定了环境文件(加载顺序通常是 /etc/profile、〜/.bash_profile、〜/.bashrc、/etc/bashrc 等), 在加载了上述环境变量文件后, Shell 就开始执行 Shell 脚本中的内容。
Shell 脚本是从上至下、 从左至右依次执行每一行的命令及语句的,(shell脚本为解释型语言) 即执行完了一个命令后再执行下一个, 如果在 Shell 脚本中遇到子脚本(即脚本嵌套) 时, 就会先执行子脚本的内容, 完成后再返回父脚本继续执行父脚本内后续的命令及语句。
通常情况下, 在执行 Shell 脚本时, 会向系统内核请求启动一个新的进程, 以便在该进程中执行脚本的命令及子 Shell 脚本。
执行方法:
- 当脚本没有执行权限时:
sh 路径/脚本名
#或
bash 路径/脚本名
建议使用此种方法执行脚本,默认情况下LInux不允许文件具有执行权限
- 当脚本有执行权限时:
路径/脚本名
- 脚本没有执行权限时:
source 路径/脚本名
#或者
. 路径/脚本名
- 根据标准输入
sh < 路径/脚本名
bash < 路径/脚本名
#或
cat 路径/脚本名 | sh
cat 路径/脚本名 | bash
三、shell脚本中的变量
变量可分为两类: 环境变量(全局变量) 和普通变量(局部变量)
- 环境变量也可称为全局变量, 可以在创建它们的 Shell 及其派生出来的任意子进程Shell 中使用, 环境变量又可分为自定义环境变量和 bash 内置的环境变量。
- 普通变量也可称为局部变量, 只能在创建它们的 Shell 函数或 Shell 脚本中使用。 普通变量一般由开发者在开发脚本程序时创建。
变量的查看
echo $变量名
变量的取消
unset 变量名
(一)环境变量(全局变量)
环境变量一般是指用 export 内置命令导出的变量, 用于定义 Shell 的运行环境, 保证 Shell 命令的正确执行。
Shell 通过环境变量来确定登录用户名、 命令路径、 终端类型、登录目录等, 所有的环境变量都是系统全局变量,可用于所有子进程中, 这包括编辑器、 Shell 脚本和各类应用。
环境变量可以在命令行中设置和创建, 但用户退出命令行时这些变量值就会丢失,因此, 如果希望永久保存环境变量, 可在用户家目录下的 .bash_profile 或 .bashrc (非用户登录模式特有, 例如远程 SSH) 文件中, 或者全局配置 /etc/bashrc (非用户登录模式特有, 例如远程 SSH ) 或 /etc/profile 文件中定义。 在将环境变量放入上述的文件中后,每次用户登录时这些变量都将被初始化。
按照系统规范, 所有环境变量的名字均采用大写形式。 在将环境变量应用于用户进程程序之前, 都应该用export 命令导出定义
有一些环境变量, 比如 HOME、PATH、SHELL等, 在用户登录之前就已经被 /bin/login 程序设置好了。 通常环境变量被定义并保存在用户家目录下的 .bash_profile 文件或全局的配置文件 /etc/profile 中
系统变量 | 含义 |
---|---|
BASH_VERSION | 保存Bash实力版本 |
HISTFILE | 命令历史文件 |
HISTFILESIZE | 命令历史文件中能包含的最大行数 |
HISTSIZE | 命令历史中的命令数 |
HOME | 家目录 |
HOSTNAME | 主机名 |
PATH | 搜索命令的路径 |
PS1 | 命令提示符 |
PWD | 当前工作目录 |
SHELL | 设置登录Shell的路径 |
TERM | 设置登录的终端的类型 |
TMOUT | 用户无操作指定时间后将自动断开终端 |
查看设置的变量
- set
显示用户的局部变量和用户环境变量
set -o 命令显示bash Shell 的所有参数配置信息 - env
显示当前用户的环境(全局)变量 - declare
输出所有的变量、 函数、 整数和已经导出的变量 - export
显示导出成用户变量的shell局部变量,并显示变量的属性;即显示由局部变量导出成环境变量的变量
自定义环境变量
1. 临时生效
① export
export 变量名=value
#或
变量名=value;export 变量名
② declare
declare -x 变量名=value
以上方式定义的环境变量,当退出bash后便不存在
2. 永久生效
永久生效即就是将定义的变量写入文件中
① 用户的环境变量配置
在~/.bashrc文件中优先设置生效,然后是~/.bash_profile文件
② 全局的环境变量配置
配置文件为:
/etc/profile
/etc/bashrc
/etc/profile.d/
优先在/etc/bashrc中设置,如果要在登陆后初始化或者显示加载内容,可以将写好的变量配置文件放在/etc/profile.d/下即可(无需加执行权限)
设置登录提示的几种方式:
- /etc/motd
- /etc/issue
- /etc/profile.d/下增加脚本
环境变量初始化与对应文件的生效顺序
在登录Linux系统时,系统登录并启动一个默认的shell环境,默认是bash shell,默认情况下,bash会在若干个文件中去查找读取环境变量,这些文件统称为系统环境文件。bash检查的环境变量文件的顺序取决于系统运行Shell的方式。
系统运行shell的方式一般有3种:
- 通过系统用户登录后默认运行的Shell。
- 非交互式登录运行Shell。
- 执行脚本运行非交互式Shell。
(一) 交互式shell加载顺序(用户登录Linux系统时):
- Shell会首先加载/etc/profile全局环境变量文件,这是默认的主环境变量文件,系统所有用户登录都会加载这个文件。
- 然后加载/etc/profile.d/下的脚本文件。
- 接下来加载用户家目录下.bash_profile(用户环境变量文件)
- 再加载家目录下.bashrc文件,如果有,则执行,如果没有则不执行
- 最后加载/etc/bashrc(全局环境变量文件),如果有则执行,如果没有则不执行。
即交互式shell加载环境变量文件的顺序: /etc/profile --> /etc/profile.d*.sh --> ~/.bash_profile --> ~/.bashrc --> /etc/bashrc
(二) 非交互式shell加载顺序:
非交互式shell只会加载 ~/.bashrc(用户环境变量文件)和 /etc/bashrc文件(全局环境变量文件)
(二)普通变量(局部变量)
只作用于变量定义的进程中,使用set命令显示出所有的变量,其中包括执行env显示的全局环境变量,剩下的变量即为本地变量
局部变量的定义:
变量名=value
当内容为简单的连续数字,字符串等时可以这样用;值里有变量时,会被解析出变量值;当变量值有空格、制表符、换行等时不能使用这种方法定义
变量名=‘value’
引号内的值是什么就输出什么,不会解析,当值中有变量或者命令(命令用反引号)也只会原样输出;适合不希望有解析的场景
变量名=”value“
会将值中的变量进行解析;适合希望将变量值中的变量解析出来并且变量值中有空格、制表符等的场景
变量名=`value`
此时的value 只能是命令;会将value(命令)解析后再赋值
变量名=$(commond)
同上,使用一个命令的结果来赋值
变量名一般由字母、数字、下划线组成,要能做到见名知义。变量的值可以用单引号,双引号或者不加引号
(三)shell进程的特殊状态变量
1. 状态变量
状态变量 | 作用说明 |
---|---|
$? | 获取执行上一个指令的执行状态返回值,返回0表示上一个命令或者程序执行成功,返回的值为非0则表示上一个命令执行失败 |
$$ | 获取当前执行的shell脚本的进程号PID |
$! | 获取上一个后台工作的进程的进程号PID |
$_ | 获取在此之前执行的命令或脚本的最后一个参数 |
$? 是一个特殊变量,用来获取上一个命令的退出状态,或者上一个函数的返回值
所谓退出状态,就是上一个命令执行后的返回结果。退出状态是一个数字,一般情况下,大部分命令执行成功会返回 0,失败返回 1;也有一些命令返回其他值,表示不同类型的错误。
所以利用 $? 变量,可以判断命令执行是否成功,快速检查自己的执行的命令是否成功。
$?返回值的常见用法:
- 判断命令,脚本等程序执行是否成功
- 在脚本中执行了exit 数字,则会将这个数字返回给$?变量
- 在函数中使用return 数字,则会把这个数字做当函数返回值传给$?变量
2. 扩展变量
表达式 | 说明 |
---|---|
${parameter:-word} | 如果parameter的变量值为空或者未赋值,则会返回word字符串代替变量值 |
${parameter:=word} | 如果parameter的变量值为空或者未赋值,则设置这个变量值为word,并返回其值 |
${parameter:?word} | 如果parameter的变量值为空或者未赋值,那么word字符串会被当做标准错误输出,否则输出变量的值 |
${parameter:+word} | 如果parameter的变量值为空或者未赋值,则什么都不做,否则word字符串将被替代变量的值 |
3. 位置参数变量
在Shell中存在一些特殊的环境变量,例如 #,#*,我们称为位置参数变量,要给命令,脚本等传递参数时,就需要在Shell脚本中使用位置参数变量。
运行 Shell 脚本文件时我们可以给它传递一些参数,这些参数在脚本文件内部可以使用$n的形式来接收,例如,$1 表示第一个参数,$2 表示第二个参数,依次类推。
同样,在调用函数时也可以传递参数。
这种通过$n的形式来接收的参数,在 Shell 中称为位置参数。
在讲解变量的命名时,我们提到:变量的名字必须以字母或者下划线开头,不能以数字开头;但是位置参数却偏偏是数字,这和变量的命名规则是相悖的,所以我们将它们视为“特殊变量”。
位置变量 | 作用说明 |
---|---|
$0 | 获取当前执行的Shell脚本的文件名,如果执行的脚本包含了路径,那么就包括脚本的路径 |
$n | 获取当前执行的Shell脚本的第n个参数值,当n=0时表示脚本的文件名,n>9时需要用大括号括起来${10} |
$# | 获取当前执行的脚本的参数的总个数 |
$* | 获取当前Shell脚本所有传递的参数,不加引号和$@相同,如果给$*加上了双引号,则将所有的参数视为单个字符串,相当于" $1 $2 $3 " |
$@ | 获取当前Shell脚本所有传递的参数,不加引号和$*相同,如果加了双引号则便是所有的参数视为不同的独立的字符串,相当于“$1”,"$2","$3";$*和$@不加双引号的时候意义相同 |
给脚本文件传递位置参数
[root@eddy ~]# cat test.sh
#!/bin/bash
echo "Name:$1"
echo "age:$2"
echo -e "当前脚本的文件名为:$0 \n当前脚本参数个数为:$# \n当前脚本的所有参数为:$* "
[root@eddy ~]sh test.sh zhangsan 18
Name:zhangsan
age:18
当前脚本的文件名为:test.sh
当前脚本参数个数为:2
当前脚本的所有参数为:zhangsan 18
其中"zhangsan"是第一个位置参数,"18"是第二个位置参数,两者之间以空格分隔。
[root@eddy ~]# sh test.sh zhangsan 18 what
Name:zhangsan
age:18
当前脚本的文件名为:test.sh
当前脚本参数个数为:3
当前脚本的所有参数为:zhangsan 18 what
该脚本只需要两个($1和$2)参数,多余的参数不会影响脚本的正常执行,但是也会接收并进行统计参数
$n中的n指的是命令行中的第n个参数,即该脚本接收命令行的那一个参数:
[root@eddy ~]# cat test.sh
#!/bin/bash
echo "Name:$3"
echo "age:$4"
echo -e "当前脚本的文件名为:$0 \n当前脚本参数个数为:$# \n当前脚本的所有参数为:$* "
[root@eddy ~]# sh test.sh zhangsan 18 lisi 19
Name:lisi
age:19
当前脚本的文件名为:test.sh
当前脚本参数个数为:4
当前脚本的所有参数为:zhangsan 18 lisi 19
如果脚本需要接收命令行参数,却未在命令行中给出参数,那么默认传递空值:
[root@eddy ~]# sh test.sh
Name:
age:
当前脚本的文件名为:test.sh
当前脚本参数个数为:0
当前脚本的所有参数为:
综合:
[root@eddy ~]# cat test.sh
#!/bin/bash
echo "Process ID: $$"
echo "File Name: $0"
echo "First Parameter : $1"
echo "Second Parameter : $2"
echo "All parameters 1: $@"
echo "All parameters 2: $*"
echo "Total: $#"
[root@eddy ~]# sh test.sh shell linux
Process ID: 1808
File Name: test.sh
First Parameter : shell
Second Parameter : linux
All parameters 1: shell linux
All parameters 2: shell linux
Total: 2
实现简单计算器:
[root@eddy ~]# cat test.sh
#!/bin/bash
if [ $# -eq 2 ]
then
echo "$1+$2=$(($1+$2))"
echo "$1-$2=$(($1-$2))"
echo "$1*$2=$(($1*$2))"
echo "$1/$2=$(($1/$2))"
else
echo "USE:$0 var1 var2"
exit 1
fi
[root@eddy ~]# sh test.sh 10 2
10+2=12
10-2=8
10*2=20
10/2=5
查看与脚本文件在同一目录下的某文件的内容
[root@eddy ~]# cat test.sh
#!/bin/bash
DIR=`dirname $0`
if [ -e $DIR/$1 ]
then
for i in `cat $1`
do
echo $i
done
else
echo "$1 not exists!"
fi
[root@eddy ~]# sh test.sh anaconda-ks.cfg
如果参数个数太多,达到或者超过了 10 个,那么就得用${n}的形式来接收了,例如 10 、 {10}、 10、{23}。{ }的作用是为了帮助解释器识别参数的边界,这跟使用变量时加{ }是一样的效果
四、内置命令
(一)echo命令
用于在屏幕上输出信息
常用选项:
- -n :不换行输出
- -e:解析转义字符
转义字符
转义字符 | 含义 |
---|---|
\a | 警告(响铃) |
\b | 退格 |
\c | 抑制更多的输出 |
\e | 转义字符 |
\f | 格式提供 |
\n | 换行 |
\r | 回车 |
\t | 横向制表符 |
\v | 纵向制表符 |
\\ | 反斜杠 |
(二) exec命令
用于调用并执行指令的命令。exec命令通常用在shell脚本程序中,可以调用其他的命令。如果在当前终端中使用命令,则当指定的命令执行完毕后会立即退出终端。
在不创建子进程的情况下去执行指定命令,并在命令执行结束后进程终止
选项:
- -c:在空环境中执行指定的命令
(三)read命令
从标准输入中读取一行&#x