目录
编辑
🐨什么是shell
🐨编译型语言和解释型语言
🐨解释型语言
🐨变量
🐨1.局部变量:
🐨2.环境变量通常又称“全局变量”
🐨3.设置环境变量:
🐨命名法则举例
🐨变量命名
🐨取消变量
🐻特殊变量
🐻1、只读变量(常量):
🐻查看常量值
🐻括号的使用
🐻位置变量
🐻$* 和 $@ 的区别。
🐻$0 引用名称的使用
🐻shift命令: 整体往左移位
🐻退出状态
什么是shell
shell 是一个命令解释器,提供用户和机器之间的交互支持特定语法,比如逻辑判断、循环每个用户都可以有自己特定的 shell还有其他 zsh 、 ksh 等CentOS7 默认的 shell 为 bash(Bourne Agin Shell)Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。 Shell 既是一种命令语言,又是一种程序设计语言。Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。shell 是一种解释型语言,这种语言经过编写后不经过任何编译就可以执行,是一种脚本语言。和编译型语言是执行前翻译不同,解释型语言的程序是执行时翻译,所以效率要差一些
编译型语言和解释型语言
优点:
编译器一般会有预编译的过程对代码进行优化。因为编译只做一次,运行时不需要编译,所以编译型语言的程序执行效率高。可以脱离语言环境独立运行。
缺点:
编译之后如果需要修改就需要整个模块重新编译。编译的时候根据对应的运行环境生成机器码,不同的操作系统之间移植就会有问题,需要根据运行的操作系统环境编译不同的可执行文件。
代表语言:
C、C++、Pascal、Object-C、swift等。
CentOS
系统中支持很多
shell,
可以通过查看
/etc/shells
文件,查看所支持的shell,目前大多数的
Linux
基本都使用
bash
[root@localhost ~]# cat /etc/shells
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash
/bin/tcsh
/bin/csh
[root@localhost ~]#
解释型语言
解释性语言的程序不需要编译,相比编译型语言省了道工序,解释性语言在运行程序的时候才逐行翻译。每一个语句都是执行的时候才能翻译。这样解释性语言每执行一次要翻译一次,效率表较低
优点:
有良好的平台兼容性,在任何环境中都可以运行,前提是安装了解释器(虚拟机)。灵活,修改代码的时候直接修改就可以,可以快速部署,不用停机维护
缺点:
每次运行的时候都要解释一遍,性能上不如编译型语言
代表语言:
JavaScript、Python、Erlang、PHP、Perl、Ruby
bash shell 有两种工作模式:互动模式和脚本模式。脚本模式效率更高,可以实现自动化[root@localhost shell]# cat kang.sh #!/bin/bash //是一个标记,告诉系统执行这个文件需要的解释器 #this line is a comment // “#”号开头的行代表注释 echo "Hello world"
1.运行脚本有两种方法
使用bash命令执行
[root@localhost shell]# bash kang.sh
Hello world
// “.”命令也都可以执行脚本,且不需要可执行权限
[root@localhost shell]# . kang.sh
Hello world
2. 、给脚本添加可执行权限,然后直接就可以执行了
[root@localhost shell]# chmod +x kang.sh
[root@localhost shell]# ./kang.sh
Hello world
PS: 脚本是各种命令的集合,终究还是要执行服务的
查看命令储蓄路径
[root@localhost bin]# echo $PATH
/usr/lib64/qt-3.3/bin:/root/perl5/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
[root@localhost bin]# cat test.sh
#!/bin/bash
ls /etc/passwd
mkdir /data
cp /etc/passwd /data/
[root@localhost bin]# chmod +x test.sh
[root@localhost bin]# test.sh
/etc/passwd
[root@localhost bin]#
变量
顾名思义,变量就是其值可以变化的量。从变量的本质来说,变量名是指向一片用于存储数据的内存空间。变量有局部变量、环境变量之分。在脚本中,往往需要使用变量来存储有用信息,比如文件名、路径名、数值等,通过这些变量可以控制脚本的运行行为
1.局部变量:
是指在某个 shell 中生效的变量,对其他 shell 来说无效,局部变量的作用域被限定在声明它们的shell 中,可以使用 local 内建命令来 “ 显式” 的声明局部变量,但仅限于函数内使用
2.环境变量通常又称“全局变量”
以区别于局部变量。在 shell 脚本中,变量默认就是全局的,为了让子shell 继承当前 shell 的变量,可以使用 export命令将其定义为环境变量
$PATH UID HOSTNAME PWD (存在内存中的)
3.设置环境变量:
第一种:
declare -x
[root@localhost shell]# declare -x class="Linux base"
[root@localhost shell]# echo $class
Linux base
第二种:
export
[root@localhost shell]# export class1="Linux"
[root@localhost shell]# echo $class1
Linux
第三种:
[root@localhost shell]# name="bj"
[root@localhost shell]# echo $name
bj
总结
总结: declare -x 和 export 这种设置变量的方式,是全局的环境变量,(全局环境变量的特点: 子进程会继承父进程的环境变量),第三种" 变量名= 变量值 " 的这种方式,默认只在当前进程有效,如果想要子进程也有效,可以使用前两种暴露的方式,或者,将变量到/etc/profile 文件中,
注意等号左右不能加空格,引号可以是单引号,也可以是双引号
,
当然也可以是引用一条命令执行后的结果(
使用反引号
[root@localhost shell]# name=`cat /etc/fstab`
[root@localhost shell]# echo $name
# # /etc/fstab # Created by anaconda on Wed Nov 2 23:38:14 2022 # # Accessible filesystems, by reference, are maintained under '/dev/disk' # See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info # /dev/mapper/centos-root / xfs defaults 0 0 UUID=1d919f48-cb52-43a9-bacb-9ea0e03a51b7 /boot xfs defaults 0 0 /dev/mapper/centos-swap swap swap defaults 0 0
//
使用反应号之后,显示格式会变化,变成了一行了。那么怎么能够显示正常那?
[root@localhost shell]# echo "$name"
#
# /etc/fstab
# Created by anaconda on Wed Nov 2 23:38:14 2022
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
/dev/mapper/centos-root / xfs defaults 0 0
UUID=1d919f48-cb52-43a9-bacb-9ea0e03a51b7 /boot xfs defaults 0 0
/dev/mapper/centos-swap swap swap defaults 0 0
[root@localhost shell]#
//
那么同样还有,变量的值也可以是一个变量
[root@localhost shell]# name=bj
[root@localhost shell]# name2=zs
[root@localhost shell]# name3=$name
[root@localhost shell]# echo $name3
bj
那么问题来了,如果我们现在把
name1
的值改了,
name3
的值是否也会跟着改变那?不会
[root@localhost shell]# name1=base
[root@localhost shell]# echo $name3
bj
[root@localhost shell]#
命名法则举例
studentname====>大驼峰 S tudent N ame, 小驼峰: student N ame (单驼峰 双驼峰 三驼峰)
变量命名
shell
中的变量必须以字母或者下划线开头,后面可以跟数字、字母和下划线,长度没有限制,区分大小写。 "
见名知意
"
变量赋值和取值
定义变量:变量名
=
变量值
注意点1:变量名和变量值之间用等号紧紧相连,之间没有任何空格
[root@localhost shell]# name=lisi
[root@localhost shell]# name= lisi
bash: lisi: 未找到命令...
[root@localhost shell]#
注意点2:当变量值中有空格时必须用引号括起,否则会出现错误,可以是双引号,也可以是单引号
[root@localhost shell]# name=li lei
bash: lei: 未找到命令...
[root@localhost shell]#
变量的取值很简单,在变量名前加
$
号就可以了,严谨的方法是
${}
。建议用后者
[root@localhost shell]# echo $name
lisi
[root@localhost shell]# echo ${name}
lisi
[root@localhost shell]#
PS:
这里注意,在很多时候,运行脚本会提示错误,仔细检查脚本后还是不确定哪里出现了问题,那么这时候不妨将变量的取值写成标准格式,说不定就会有惊喜。
取消变量
取消变量使用
unset,
后面跟变量名。函数也是可以被取消的,
unset
后面也是可以跟上函数名来取消函数的
[root@localhost shell]# unset name
[root@localhost shell]# echo ${name}
特殊变量
上边我们接触到局部变量和环境(全局)变量,也知道了他们特点:局部变量只在当前shell 有效,环境变量的有效范围为当前 shell 和子 shell 。除了这些还有其他一些变量,也需要我们注意
1、只读变量(常量):
只能声明,但不能修改和删除
[root@localhost shell]# readonly name1="wukong"
[root@localhost shell]# echo $name1
wukong
[root@localhost shell]# name1=bajie
-bash: name1: 只读变量
[root@localhost shell]#
还可以使用
declare -r
声明常量
[root@localhost shell]# declare -r name2="bajie"
[root@localhost shell]# echo $name2
bajie
[root@localhost shell]#
readonly:
有效期直到是进程结束。那么这个只读变量有什么用那?比方说pi=3.14 3.1415926
查看常量值
[root@localhost shell]# readonly -p
declare -r BASHOPTS="checkwinsize:cmdhist:expand_aliases:extglob:extquote:force_fignore:histappend:interactive_comments:login_shell:progcomp:promptvars:sourcepath"
declare -ir BASHPID
declare -r BASH_COMPLETION_COMPAT_DIR="/etc/bash_completion.d"
declare -ar BASH_REMATCH='()'
declare -ar BASH_VERSINFO='([0]="4" [1]="2" [2]="46" [3]="2" [4]="release" [5]="x86_64-redhat-linux-gnu")'
declare -ir EUID="0"
declare -ir PPID="4989"
declare -r SHELLOPTS="braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor"
declare -ir UID="0"
declare -r name1="wukong"
declare -r name2="bajie
括号的使用
小括号用法:一次性使用。不会对环境产生影响
[root@localhost shell]# (name=yjs;echo $name)
yjs
[root@localhost shell]# echo $name
[root@localhost shell]#
大括号
:前后有空格。这个是对全局有影响的。
[root@localhost shell]# { name=adam; echo $name; }
adam
[root@localhost shell]# echo $name
adam
[root@localhost shell]#
位置变量
shell
中还有一些预先定义的特殊只读变量,它们的值只有在脚本运行时才能确定
$0 :代表脚本本身名字$1----$9 :第一个位置参数 ------- 第 9 个位置参数$# :脚本参数的个数总和$@ :表示脚本的所有参数$* : 表示脚本的所有参数
[root@localhost shell]# cat example.sh
#!/bin/bash
echo "这个脚本的名字是:$0"
echo "参数一共有:$#个"
echo "参数的列表是: $@"
echo "参数的列表是: $*"
echo "第一个参数是: $1"
echo "第二个参数是: $2"
echo "第三个参数是:$3"
[root@localhost shell]#
[root@localhost shell]# bash example.sh 1 2 3 4 5
这个脚本的名字是:example.sh
参数一共有:5个
参数的列表是: 1 2 3 4 5
参数的列表是: 1 2 3 4 5
第一个参数是: 1
第二个参数是: 2
第三个参数是:3
如果有
10
个以上的数改怎么表示
[root@localhost shell]# echo {1..15}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
[root@localhost shell]# echo {a..z}
a b c d e f g h i j k l m n o p q r s t u v w x y z
[root@localhost shell]#
怎么才能让它识别为$10那?这个时候就要用到花括号了。
[root@localhost shell]# cat example.sh
#!/bin/bash
echo "这个脚本的名字是:$0"
echo "参数一共有:$#个"
echo "参数的列表是: $@"
echo "参数的列表是: $*"
echo "第一个参数是: $1"
echo "第二个参数是: $2"
echo "第三个参数是:$3"
echo "第12个参数是:${12}"
[root@localhost shell]#
[root@localhost shell]# bash example.sh {1..15}
这个脚本的名字是:example.sh
参数一共有:15个
参数的列表是: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
参数的列表是: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
第一个参数是: 1
第二个参数是: 2
第三个参数是:3
第12个参数是:12
[root@localhost shell]#
//
那么具体这个有什么用那?,其实可以这样,假设我们要复制一个文件到另一台虚拟机。用什么命令那?scp
、
[root@localhost shell]# cat /etc/redhat-release > mylrelease.txt
[root@localhost shell]# cat mylrelease.txt
CentOS Linux release 7.9.2009 (Core)
[root@localhost shell]#
$* 和 $@ 的区别。
$* 和 $@ 都代表了脚本的所有参数,但是, $* 它会把显示的结果当做一个整体显示,而$@ 会把收集到的结果分开来显示。不过要注意,如果$*和 $@ 有双引号的前提下,显示效果会做区分,如果都没有双引号,效果一样。
[root@localhost shell]# cat t1.sh
#!/bin/bash
echo "t1脚本所有参数是:$*"
bash t2.sh "$*"
[root@localhost shell]# cat t2.sh
#!/bin/bash
echo "t2脚本的第一个参数:$1"
[root@localhost shell]# bash t1.sh 1 2 3
t1脚本所有参数是:1 2 3
t2脚本的第一个参数:1 2 3
[root@localhost shell]#
把
t1.sh
中的
bash t2.sh “$*”
换成
$@
用
sed
怎么换
[root@localhost shell]# sed -i '3s/\$\*/\$\@/' t1.sh
[root@localhost shell]# bash t1.sh 1 2 3
t1脚本所有参数是:1 2 3
t2脚本的第一个参数:1
[root@localhost shell]#
$0 引用名称的使用
再来说这个
$0
,
$0
是名称,那么如果说,我把一个脚本,添加一个软连接。这个时候如果再运行脚本,那么它的$0
显示的名字应该是原来的名字那?还是更改过后的名字?
[root@localhost shell]# ln -s example.sh link.sh
[root@localhost shell]# bash link.sh
这个脚本的名字是:link.sh
参数一共有:0个
参数的列表是:
参数的列表是:
第一个参数是:
第二个参数是:
第三个参数是:
第12个参数是:
[root@localhost shell]#
那么以后我们就可以利用这一点,即便是同一个脚本,到时候也可以拓展出不同的功能。比如说,就可以利用这一点。那么就可以让他们返回的值是不一样的。这个就是以后在写脚本的时候,就要注意下,需要对$0
做判断了。
shift命令: 整体往左移位
[root@localhost shell]# cat example.sh
#!/bin/bash
echo "这个脚本的名字是:$0"
echo "参数一共有:$#个"
echo "参数的列表是: $@"
echo "参数的列表是: $*"
echo "第一个参数是: $1"
echo "第二个参数是: $2"
echo "第三个参数是:$3"
echo "第12个参数是:${12}"
shift
echo "这个脚本的名字是:$0"
echo "参数一共有:$#个"
echo "参数的列表是: $@"
echo "参数的列表是: $*"
echo "第一个参数是: $1"
echo "第二个参数是: $2"
echo "第三个参数是:$3"
echo "第12个参数是:${12}"
shift
echo "这个脚本的名字是:$0"
echo "参数一共有:$#个"
echo "参数的列表是: $@"
echo "参数的列表是: $*"
echo "第一个参数是: $1"
echo "第二个参数是: $2"
echo "第三个参数是:$3"
echo "第12个参数是:${12}"
[root@localhost shell]#
PS : 当然这是默认的移动一位,当然也可以通过设置决定移动多少位,在shift 后边直接加上想要移动的位数即可。
退出状态
进程使用退出状态来报告成功或者失败:
$
? 变量保存最近的命令退出状态
0
代表成功,
1~255
代表失败
举例
[root@localhost shell]# ls /tmp/
systemd-private-5d5242bfa7a445ff929e39dfdd38104b-bolt.service-eJViXd
systemd-private-5d5242bfa7a445ff929e39dfdd38104b-chronyd.service-AhBuTC
systemd-private-5d5242bfa7a445ff929e39dfdd38104b-colord.service-IMbJvs
systemd-private-5d5242bfa7a445ff929e39dfdd38104b-cups.service-N5SsIj
systemd-private-5d5242bfa7a445ff929e39dfdd38104b-rtkit-daemon.service-63nbw5
systemd-private-e403b5d9448d4c048c3a7f654f134ba8-bolt.service-MNeFrF
systemd-private-e403b5d9448d4c048c3a7f654f134ba8-chronyd.service-A8qNGd
systemd-private-e403b5d9448d4c048c3a7f654f134ba8-colord.service-WUjrtE
systemd-private-e403b5d9448d4c048c3a7f654f134ba8-cups.service-eCfKFF
systemd-private-e403b5d9448d4c048c3a7f654f134ba8-rtkit-daemon.service-IQMGcU
yum_save_tx.2023-07-06.15-27.Jcn602.yumtx
[root@localhost shell]# echo $?
0
[root@localhost shell]# ls /apc
ls: 无法访问/apc: 没有那个文件或目录
[root@localhost shell]# echo $?
2
[root@localhost shell]# id test &> /dev/null
[root@localhost shell]# echo $?
1
[root@localhost shell]#
当然判断命令是否执行成功,不仅仅是简单的判断$? 还有更严谨的判断语句,这个我们以后会讲,现在先知道就可以了。那么在这里还需要知道一点。我们的脚本里边,往往是大于一条命令的,这个$? 返回的 0 值,如果返回的是0, 那么这个 0值到底是返回的哪一条命令的值那?
[root@localhost shell]# cat test1.sh
#!/bin/bash
hostname
[root@localhost shell]# bash test1.sh
localhost.localdomain
[root@localhost shell]# echo $?
0
[root@localhost shell]#
这是一条命令,如果是多秒命令那
?
,这里故意将上述明林写错试一下
[root@localhost shell]# cat test1.sh
#!/bin/bash
hostnam
[root@localhost shell]# bash test1.sh
test1.sh:行2: hostnam: 未找到命令
[root@localhost shell]# echo $?
127
[root@localhost shell]# cat test1.sh
#!/bin/bash
hostnam
ls
[root@localhost shell]# bash test1.sh
test1.sh:行2: hostnam: 未找到命令
example.sh kang.sh link.sh mylrelease.txt t1.sh t2.sh test1.sh
[root@localhost shell]# echo $?
0
[root@localhost shell]#
说明,
$?
通常只返回最后一条命令的状态。但不是绝对,因为还有另外一种情况。比如语法错误
[root@localhost shell]# cat test1.sh
#!/bin/bash
if
ls
[root@localhost shell]# bash test1.sh
test1.sh:行4: 语法错误: 未预期的文件结尾
[root@localhost shell]# echo $?
2
[root@localhost shell]#
再还有,只要返回的不是
0
,肯定是错误的那?也是不一定的。因为
$?
的返回值,是可以修改的。
正常的
$0
[root@localhost shell]# cat test1.sh
#!/bin/bash
ls
[root@localhost shell]# bash test1.sh
example.sh kang.sh link.sh mylrelease.txt t1.sh t2.sh test1.sh
[root@localhost shell]# echo $?
0
[root@localhost shell]#
修改退出状态码
[root@localhost shell]# cat test1.sh
#!/bin/bash
ls
exit 10
[root@localhost shell]# bash test1.sh
example.sh kang.sh link.sh mylrelease.txt t1.sh t2.sh test1.sh
[root@localhost shell]# echo $?
10
[root@localhost shell]#
PS : 那么我们就要考虑,根据不同的返回码,我们是不是就可判断出系统的运行状态啊? 假设说,我们规定了计算机会有几种情况,如果说一种情况返回10 ,另一种情况返回 20 ,还有 30 ,那么我们就可根据系统返回的值的不同,来判断出,系统肯定是满足了某种条件。这样就可以作为定位判断系统状态的依据,其实在我们上网的时候有返回发 404 ,其实也是类似这种方法的。200 OK 404 Not Found3xx重定向 4xx 客户端错误 5xx 服务器错误当然exit 命令在外部也可以使用,意思是退出 bash