Linux笔记 No.27---(shell脚本编程)

文章目录

一、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 脚本。

执行方法:

  1. 当脚本没有执行权限时:
sh 路径/脚本名    
#或
bash 路径/脚本名   

建议使用此种方法执行脚本,默认情况下LInux不允许文件具有执行权限

  1. 当脚本有执行权限时:
路径/脚本名
  1. 脚本没有执行权限时:
source 路径/脚本名
#或者
. 路径/脚本名
  1. 根据标准输入
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

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值