什么是shell

shell是一个命令解释器,提供用户和机器之间的交互

支持特定语法,比如逻辑判断、循环

每个用户都可以有自己特定的shell

还有其他zsh、ksh等

CentOS7 默认的shell为bash(Bourne Agin Shell)

Shell是一个用C语言编写的程序,它是用户使用Linux的桥梁。Shell既是一种命令语言,又是一种程序设计语言。

Shell是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。

shell是一种解释型语言,这种语言经过编写后不经过任何编译就可以执行,是一种脚本语言。和编译型语言是执行前翻译不同,解释型语言的程序是执行时翻译,所以效率要差一些。

1,编译型语言和解释型语言:

优点: 编译器一般会有预编译的过程对代码进行优化。因为编译只做一次运行时不需要编译,所以编译型语言的程序执行效率高。可以脱离语言环境独立运行。

缺点: 编译之后如果需要修改就需要整个模块重新编译。编译的时候根据对应的运行环境生成机器码,不同的操作系统之间移植就会有问题,需要根据运行的操作系统环境编译不同的可执行文件。

代表语言: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

解释型语言

解释性语言的程序不需要编译,相比编译型语言省了道工序,解释性语言在运行程序的时候才逐行翻译。每一个语句都是执行的时候才能翻译。这样解释性语言每执行一次要翻译一次,效率表较低。

优点: 有良好的平台兼容性,在任何环境中都可以运行,前提是安装了解释器(虚拟机)。灵活,修改代码的时候直接修改就可以,可以快速部署,不用停机维护。

缺点: 每次运行的时候都要解释一遍,性能上不如编译型语言。

代表语言:JavaScript、 Python、 Erlang、 PHP、 Perl、 Ruby

bash shell有两种工作模式:互动模式和脚本模式。脚本模式效率更高,可以实现自动化。

编写第一个shell脚本:

[root@localhost shell]# cat helloworld.sh
#!/bin/bash         // 是一个标记, 告诉系统执行这个文件需要的解释器
#this line is a comment           //  "#"号开头的行代表注释
echo "hello world"

运行脚本的两种方法:

1, 使用bash命令执行

[root@localhost shell]# bash helloworld.sh
hello world

// "."命令也都可以执行脚本,且不需要可执行权限

[root@localhost shell]# . helloworld.sh
hello world

2,给脚本添加可执行权限,然后直接就可以执行了

[root@localhost shell]# chmod +x helloworld.sh
[root@localhost shell]# ./helloworld.sh
hello world

PS:脚本是各种命令的集合,终究还是要执行服务的。

3,查看命令存储路径

[root@localhost bin]# echo $PATH
/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

变量

顾名思义,变量就是其值可以变化的量。从变量的本质来说,变量名是指向一片用于存储数据的内存空间。变量有局部变量、环境变量之分。在脚本中,往往需要使用变量来存储有用信息,比如文件名、路径名、数值等,通过这些变量可以控制脚本的运行行为。

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="ghran"
[root@localhost shell]# echo $name
ghran

总结: declare -x 和 export 这种设置变量的方式, 是全局的环境变量,(全局环境变量的特点:子进程会继承父进程的环境变量),第三种"变量名=变量值"的这种方式,默认只在当前进程有效, 如果想要子进程也有效,可以使用前两种暴露的方式,或者,将变量添到/etc/profile文件中

[root@localhost shell]# vim /etc/profile
[root@localhost shell]# tail -n 5 /etc/profile
doneunset i
unset -f pathmunge
export name="ghran ran"  //添加
[root@localhost shell]# source /etc/profile
[root@localhost shell]# echo $name
ghran ran

注意: 等号左右不能添加空格,引号可以是单引号,也可以是双引号,当然也可以是引用一条命令执行后的结果(使用反引号)。

[root@localhost shell]# name=`cat /etc/fstab`
[root@localhost shell]# echo $name#  #/etc/fstab # Created by anaconda on Thu May 21 19:51:04 2020 # # 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=02a784a5-a1d8-4132-979c-ab0618cddbd2 /boot xfs defaults 0 0 /dev/mapper/centos-home /home xfs defaults 0 0 /dev/mapper/centos-swap swap swap defaults 0 0

//使用反引号之后,显示格式会变化,变成了一行了。那么怎么能够显示正常那?

[root@localhost shell]# echo "$name"#
#/etc/fstab
#Created by anaconda on Thu May 21 19:51:04 2020
#
#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=02a784a5-a1d8-4132-979c-ab0618cddbd2 /boot                   xfs     defaults        0 0
/dev/mapper/centos-home /home                   xfs     defaults        0 0
/dev/mapper/centos-swap swap                    swap    defaults        0 0

//那么同样还有,变量的值也可以是一个变量。

[root@localhost shell]# name1=g
[root@localhost shell]# name2=gh
[root@localhost shell]# name3=$name1
[root@localhost shell]# echo $name3
g
如果我们现在把name1的值改了, name3的值是否也会跟着改变?   //不会
[root@localhost shell]# name1=ghran
[root@localhost shell]# echo $name3
g

命名法则举例:

studentname====>大驼峰StudentName,小驼峰:studentName (单驼峰 双驼峰 三驼峰)

变量命名

shell中的变量必须以字母或者下划线开头,后面可以跟数字、字母和下划线,长度没有限制,区分大小写。 “见名知意”

变量赋值和取值

定义变量:变量名=变量值

注意点1:变量名和变量值之间用等号紧紧相连,之间没有任何空格

[root@localhost shell]# name=john
[root@localhost shell]# name= john
-bash: john: command not found

注意点2:当变量值中有空格时必须用引号括起,否则会出现错误, 可以是双引号,也可以是单引号

[root@localhost shell]# name=li lei
-bash: lei: command not found
[root@localhost shell]# name="li lei"
[root@localhost shell]# echo $name
li lei
[root@localhost shell]# name='li lei'
[root@localhost shell]# echo $name
li lei

变量的取值很简单,在变量名前加 $号就可以了, 严谨的方法是 ${}。 建议用后者

[root@localhost shell]# echo $name
li lei
[root@localhost shell]# echo ${name}
li lei
PS:这里注意,在很多时候,运行脚本会提示错误,仔细检查脚本后还是不确定哪里出现了问题,那么这时候不妨将变量的取值写成标准格式,说不定就会有惊醒

取消变量

取消变量使用unset,后面跟变量名。函数也是可以被取消的,unset后面也是可以跟上函数名来取消函数的。

[root@localhost shell]# unset name
[root@localhost shell]# echo ${name}

PS:当然一般在不用变量的时候,我们都会取消变量,当然退出进程也可以取消变量,但一般我们都会人为的再去取消一下用uset命令

//这里注意一下我unset的时候没有用$符号,一般引用的时候加 $符号,也就是说前面的命令如果识别不出来变量的时候,就像我们用echo的时候,如果你不加 $符号,他会把后面的当做字符串

set命令可以显示所有变量:包括局部变量和环境变量。也会显示一些函数。
env, printenv, export, declare -x也可以。

特殊变量

上边我们接触到局部变量和环境(全局)变量,也知道了他们特点:局部变量只在当前shell有效,环境变量的有效范围为当前shell和子shell。除了这些还有其他一些变量,也需要我们注意。

1,只读变量(常量):

只能声明,但不能修改和删除

[root@localhost shell]# readonly name1="wukong"
[root@localhost shell]# echo $name1
wukong
[root@localhost shell]# name1=bajie
-bash: name1: readonly variable

还可以使用declare -r 声明常量。

[root@localhost shell]# declare  -r  name2="bajie"
[root@localhost shell]# echo $name2
bajie

readonly:有效期直到是进程结束。那么这个只读变量有什么用那?比方说pi=3.14 3.1415926

//查看常量值

[root@localhost shell]# readonly -p

2,括号的使用

小括号用法: 一次性使用。不会对环境产生影响。

[root@localhost shell]# (name=yjs;echo $name)
yjs
[root@localhost shell]# echo $name

大括号: 前后有空格。这个是对全局有影响的。

[root@localhost shell]# { name=ghran; echo $name; }
ghran
[root@localhost shell]# echo $name
ghran

3,位置变量

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]# 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

怎么才能让它识别为$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]# 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

//那么具体这个有什么用那?,其实可以这样,假设我们要复制一个文件到另一台虚拟机。用什么命令那?scp?

[root@localhost shell]# cat /etc/redhat-release > myrelease.txt
[root@localhost shell]# cat myrelease.txt
CentOS Linux release 7.6.1810 (Core)

//可以用脚本来写

[root@localhost shell]# cat scp.sh
#!/bin/bash
scp $1 root@192.168.1.20:/root/
[root@localhost shell]# bash scp.sh myrelease.txt
root@192.168.1.20's password:
myrelease.txt               100%   38    24.0KB/s   00:00

//当然还可以继续完善脚本。写的人性化一些。

[root@localhost shell]# cat scp.sh
#!/bin/bash
#start copy
echo "copying ..."
scp $1 root@192.168.1.20:/root/
echo "copy is finished!"
[root@localhost shell]# bash scp.sh myrelease.txt
copying ...
root@192.168.1.20's password:
myrelease.txt                100%   38    21.6KB/s   00:00
copy is finished!

//免密登录。传东西不用输入密码。

[root@localhost shell]# ssh-keygen -t rsa   //连续3下空格
[root@localhost shell]# ssh-copy-id root@192.168.1.20
[root@localhost shell]# bash scp.sh myrelease.txt
copying ...
myrelease.txt           100%   38    26.6KB/s   00:00
copy is finished

//那么如果要传送多个文件,这个脚本该怎么写? 把$1 改成 $* ? 那么用sed语句应该怎么写?

[root@localhost shell]# touch r{1..5}.txt
[root@localhost shell]# cat scp.sh
#!/bin/bash
#start copy
echo -e  "\e[1;31mstart copy...\e[0m"   //给start copy添加颜色
sleep 5            //将目前动作延迟5s
scp $*  root@192.168.1.20:/root/
#end copy
echo -e "\e[1;31mcopy is finished\e[0m" //给copy is finished 添加颜色
[root@localhost shell]# bash scp.sh r1.txt r2.txt r3.txt r4.txt
start copy...
r1.txt                      100%    0     0.0KB/s   00:00
r2.txt                      100%    0     0.0KB/s   00:00
r3.txt                      100%    0     0.0KB/s   00:00
r4.txt                      100%    0     0.0KB/s   00:00
copy is finished

#$* 和 $@ 的区别

$* 和 $@ 都代表了脚本的所有参数,但是, $*它会把显示的结果当做一个整体显示,而 $@会把收集到的结果分开来显示。不过要注意,如果 $*和 $@有双引号的前提下,显示效果会做区分,如果都没有双引号,效果一样。

//理论上,r2脚本的第一个参数,显示的并不正确。

[root@localhost shell]# cat r1.sh
#!/bin/bash
echo "r1脚本所有参数是:$*"
bash r2.sh "$*"
[root@localhost shell]# cat r2.sh
#!/bin/bash
echo "r2脚本的第一个参数:$1"
[root@localhost shell]# bash r1.sh a b c d
r1脚本所有参数是:a b c d
r2脚本的第一个参数:a b c d

//把r1.sh中 bash t2.sh “$*” 换成 $@ 用 sed 换。

[root@localhost shell]# sed -i '3s/\$\*/\$\@/' r1.sh
[root@localhost shell]# cat r1.sh
#!/bin/bash
echo "r1脚本所有参数是:$*"
bash r2.sh "$@"
[root@localhost shell]# bash r1.sh a b c d
r1脚本所有参数是:a b c d
r2脚本的第一个参数:a

$0 引用名称的使用

再来说这个$0,$0是名称,那么如果说,我把一个脚本,添加一个软连接。这个时候如果再运行脚本,那么它的$0显示的名字应该是原来的名字那?还是更改过后的名字?

[root@base shell]# ln -s example.sh link.sh
[root@base shell]# bash link.sh
这个脚本的名字是:link.sh
参数一共有:0个
参数的列表是:
....

那么以后我们就可以利用这一点,即便是同一个脚本,到时候也可以拓展出不同的功能。比如说,就可以利用这一点。那么就可以让他们返回的值是不一样的。这个就是以后在写脚本的时候,就要注意下,需要对$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}"

PS :当然这是默认的移动一位,当然也可以通过设置决定移动多少位,在shift 后边直接加上想要移动的位数即可。

4,退出状态

进程使用退出状态来报告成功或者失败:
· $? 变量保存最近的命令退出状态
· 0 代表成功, 1~255 代表失败

举例:

[root@localhost shell]# ls /tmp
ks-script-VfFALz           vmware-root_6332-692686615   yum.log
vmware-root_6311-1714754901  vmware-root_6345-1950163716
[root@localhost shell]# echo $?
0
[root@localhost shell]# ls /abc
ls: cannot access /abc: No such file or directory
[root@localhost shell]# echo $?
2
[root@localhost shell]# id root &> /dev/null
[root@localhost shell]# echo $?
0

那么在这里还需要知道一点。我们的脚本里边,往往是大于一条命令的,这个 $?返回的0值,如果返回的是0,那么这个0值到底是返回的哪一条命令的值那?

[root@base shell]# cat test1.sh
#!/bin/bash
hostname
[root@base shell]# bash test1.sh
base
[root@base shell]# echo $?
0

//这是一条命令,如果是多条命令呢?这里故意将上述明林写错试一下

[root@base shell]# cat test1.sh
#!/bin/bash
hostnam
[root@base shell]# bash test1.sh
test1.sh: line 2: hostnam: command not found
[root@base shell]# echo $?
127
[root@base shell]# cat test1.sh
#!/bin/bash
hostnam
ls
[root@base shell]# bash test1.sh
test1.sh: line 2: hostnam: command not found
example.sh Helloworld.sh link.sh mylrelease.txt scp.sh
t1.sh t2.sh test1.sh
[root@base shell]# echo $?
0

//说明,$?通常只返回最后一条命令的状态。但不是绝对,因为还有另外
一种情况。比如语法错误。

[root@base shell]# cat test1.sh
#!/bin/bash
if
ls
[root@base shell]# bash test1.sh
test1.sh: line 4: syntax error: unexpected end of file
[root@base shell]# echo $?
2

//再还有,只要返回的不是0,肯定是错误的那?也是不一定的。因为$?的
返回值,是可以修改的。
//正常的$0

[root@base shell]# cat test1.sh
#!/bin/bash
ls
[root@base shell]# bash test1.sh
example.sh Helloworld.sh link.sh mylrelease.txt scp.sh
t1.sh t2.sh test1.sh
[root@base shell]# echo $?
0

//修改退出状态码

[root@base shell]# cat test1.sh
#!/bin/bash
ls
exit 10
[root@base shell]# bash test1.sh
example.sh Helloworld.sh link.sh mylrelease.txt scp.sh
t1.sh t2.sh test1.sh
[root@base shell]# echo $?
10

PS : 那么我们就要考虑,根据不同的返回码,我们是不是就可判断出系统的运行状态啊?假设说,我们规定了计算机会有几种情况,如果说一种情况返回10,另一种情况返回20,还有30,那么我们就可根据系统返回的值的不同,来判断出,系统肯定是满足了某种条件。这样就可以作为定位判断系统状态的依据,其实在我们上网的时候有返回发404,其实也是类似这种方法的。200 OK 404 Not Found

 3xx重定向        4xx客户端错误         5xx服务器错误

当然exit命令在外部也可以使用,意思是退出bash

数组

数组是一种特殊的数据结构,其中的每一项被称为一个元素,对于每个元素,都可以用索引的方式取出元素的值。使用数组的典型场景是一次性要记录很多类型相同的数据时(但不一定必须要相同)。比如,为了记录班级中所有人的数学成绩,如果不用数据来处理,那就只能定义所有人成绩的变量。shell中的数组对元素个数没有限制,但只支持一维数组。

1,定义数组

//使用declare命令定义数组

[root@base shell]# declare -a List
[root@base shell]# List[0]=Tom
[root@base shell]# List[1]=Jerry
[root@base shell]# List[2]=Dog
[root@base shell]# echo ${List[0]}
Tom
[root@base shell]# echo ${List[1]}
Jerry
[root@base shell]# echo ${List[2]}
Dog

//当然,也可以在创建数组的同时赋值,declare -a也可以省略不写

[root@base shell]# Name=("zhangsan" "li si" "wang wu")
[root@base shell]# echo ${Name[0]}
zhangsan
[root@base shell]# echo ${Name[1]}
li si
[root@base shell]# echo ${Name[2]}
wang wu

//也可以用负数,表示倒叙

[root@base shell]# echo ${Name[-1]}
wang wu
[root@base shell]# echo ${Name[-2]}
li si
[root@base shell]# echo ${Name[-3]}
zhangsan

PS: 注意数组多个元素之间,不要用符号,否则会把多个元素当做整体一起输出。

[root@base shell]# name=("zhangsan","li si","wang wu")
[root@base shell]# echo $name
zhangsan,li si,wang wu
[root@base shell]# echo ${name[0]}
zhangsan,li si,wang wu
[root@base shell]# echo ${name[1]}

//还可以使用跳号赋值,也就是说可以指定索引号。

[root@base shell]# Score=([3]=3 [5]=5 [7]=7)
[root@base shell]# echo ${Score[3]}
3
[root@base shell]# echo ${Score[5]}
5
[root@base shell]# echo ${Score[7]}
7

2、数组的取值

数组取值:格式为: ${数组名[索引]}

默认显示数字第一个元素值

[root@base shell]# echo ${Name[0]}
zhangsan
[root@base shell]# echo ${Name}
zhangsan

取出对应索引下标的值

[root@base shell]# echo ${Name[2]}
wang wu
[root@base shell]# echo ${Name[1]}
li si
[root@base shell]# echo ${Name[0]}
zhangsan

PS: 注意的是,数组内索引为0 的才是第一个。

3、一次取出数组所有的值

@ //得到的是以空格隔开的元素
[root@base shell]# echo ${Name[@]}
zhangsan li si wang wu
*  //得到的是一整个字符串
[root@base shell]# echo ${Name[*]}
zhangsan li si wang wu

4、数组长度: 即数组元素个数

利用“@”或“*”字符,可以将数组扩展成列表,然后使用“#”来获取数组元素
的个数。

[root@base shell]# echo ${#Name[*]}
3
[root@base shell]# echo ${#Name[@]}
3

5、数组的截取(分片)(切片)

可以截取某个元素的一部分,对象可以是整个数组或某个元素。(数组的
切片:右不包括行为)

//定义数组

[root@base shell]# Number=(1 2 3 4 5 6 7 8)
[root@base shell]# echo ${Number[*]}
1 2 3 4 5 6 7 8
[root@base shell]# echo ${#Number[*]}
8

//取出第一个到第3个元素的值

[root@base shell]# echo ${Number[@]:0:3}
1 2 3

//取出第3个到第6个元素的值

[root@base shell]# echo ${Number[@]:2:4}
3 4 5 6

PS: 注意,数组分片的书写格式的意义表示:从第几个开始连续出现几个字符。
//也可以取出某个元素的第几个开始到第几个字符

[root@base shell]# Word=(hello world and welcome)
[root@base shell]# echo ${Word[2]:0:3}
and
[root@base shell]# echo ${Word[1]:0:3}
wor
[root@base shell]# echo ${Word[1]:0:4}
worl

6、连接数组

将若干个数组进行拼接操作

[root@base shell]# echo ${Number[@]}
1 2 3 4 5 6 7 8
[root@base shell]# echo ${Word[@]}
hello world and welcome

//将两个数组的元素全部连接

[root@base shell]# NewNum=(${Number[@]} ${Word[@]})
[root@base shell]# echo $NewNum
1
[root@base shell]# echo ${NewNum[@]}
1 2 3 4 5 6 7 8 hello world and welcom

//那么现在我们重组新的数组,截取Word数组的第2个元素从第0个连续5个字符,和Number数组里的第2个字符开始连续3个字符。

[root@base shell]# New=(${Word[2]:0:5} ${Number[@]:1:3})
[root@base shell]# echo ${New[@]}
and 2 3 4

7、替换元素

将数组内某个元素的值替换成其他值。如果匹配不到则没有改动

[root@base shell]# Name=(zhangsan lisi wangwu zhaoliu)
[root@base shell]# echo ${Name[@]}
[root@base shell]# echo ${Name[@]}
zhangsan lisi wangwu zhaoliu
//将lisi替换为lilei
[root@base shell]# Name=(${Name[@]/lisi/lilei})
[root@base shell]# echo ${Name[@]}
zhangsan lilei wangwu zhaoliu
//将zhaoliu替换为zhaosi
[root@base shell]# Name=(${Name[@]/zhaoliu/zhaosi})
[root@base shell]# echo ${Name[@]}
zhangsan lilei wangwu zhaosi

//上边的写法可以达到要求,但较为复杂,其实可以完全按照“变量” 重新赋值的方式,直接写数组的对应的元素的值。比如,上述例子中将zhangsan改为 :wukong,就可以简化为

[root@base ~]# Name[0]=wukong
[root@base ~]# echo ${Name[@]}
wukong lilei wangwu zhaosi

//取消数组或元素
使用unset命令,取消数组中的一个元素

[root@base shell]# unset Name[2]
[root@base shell]# echo ${Name[@]}
zhangsan lilei zhaosi

//取消整个数组,=取消变量全部

[root@base shell]# unset Name
[root@base shell]# echo ${Name[@]}
数组练习

1、设置两个变量组,groupA和groupB
groupA的成员包括:zhangsan 、lisi、wangwu、zhaoliu
groupB的成员包括:gangtiexia、zhizhuxia、heiguafu、lvjuren、meidui

[root@shell bin]# groupA=(zhangsan lisi wangsu zhaoliu)
[root@shell bin]# groupB=(gangtiexia zhizhuxia heiguafu
lvjuren meidui)

2、显示每个组的全部成员:

[root@shell bin]# echo ${groupA[@]}
zhangsan lisi wangsu zhaoliu
[root@shell bin]# echo ${groupB[@]}
gangtiexia zhizhuxia heiguafu lvjuren meidui

3、查看groupA的第2个成员。并查看groupB的第3个成员。

[root@shell bin]# echo ${groupA[1]}
lisi
[root@shell bin]# echo ${groupB[2]}
heiguafu

4、将groupA的第4个成员替换为zhaosi,groupB的第一个成员替换为heibao.

[root@shell bin]# echo ${groupA[@]}
zhangsan lisi wangsu zhaoliu
[root@shell bin]# groupA[3]=zhaosi
[root@shell bin]# echo ${groupA[@]}
zhangsan lisi wangsu zhaosi
[root@shell bin]# groupB[0]=heibao
[root@shell bin]# echo ${groupB[@]}
heibao zhizhuxia heiguafu lvjuren meidui

5、抽取groupA中的成员,和groupB中成员,组成groupC.

[root@shell bin]# groupC=(${groupA[@]} ${groupB[@]})
[root@shell bin]# echo ${groupC[@]}
zhangsan lisi wangsu zhaosi heibao zhizhuxia heiguafu
lvjuren meidui

6、显示groupC的全部成员,并且将第8个成员替换为liuneng

[root@shell bin]# echo ${groupC[@]}
zhangsan lisi wangsu zhaosi heibao zhizhuxia heiguafu
lvjuren meidui
[root@shell bin]# groupC[7]=liuneng
[root@shell bin]# echo ${groupC[@]}
zhangsan lisi wangsu zhaosi heibao zhizhuxia heiguafu
liuneng meidui

7、显示groupC的倒数第二个成员。

[root@shell bin]# echo ${groupC[-2]}
liuneng

8、显示groupC中第二个元素开始到第五个元素。

[root@shell bin]# echo ${groupC[@]:1:4}
lisi zhaosi heibao zhizhuxia
[root@shell bin]# echo ${groupC[@]}
zhangsan lisi zhaosi heibao zhizhuxia heiguafu liuneng
meidui

转义和引用

shell中有很多特殊字符,会有特殊意义,但是有时候会造成麻烦,需要转义才可以使用,转义符号为“\”

[root@localhost shell]# a=$dollar
[root@localhost shell]# echo $a[root@localhost shell]# a=\$dollar
[root@localhost shell]# echo $a
$Dollar

引用是指将字符串用某种符号括起来,以防止特殊字符被解析为其他意思。shell中一共有4种引用符,分别为双引号、单引号、反引号和转义符。双引号可以引用除$符号、反引号、转义符之外的所有字符;单引号可以引用所有字符;反引号则会将反引号中的内容解释为系统命令。

[root@base shell]# who am i
root   pts/0     2020-05-12 00:03 (192.168.1.1)
[root@base shell]# echo "who am i"
who am i
[root@base shell]# echo 'who am i'
who am i
[root@base shell]# echo `who am i`
root pts/0 2020-05-12 00:03 (192.168.1.1)
[root@base shell]# echo $PWD
/opt/shell
[root@base shell]# echo "$PWD"
/opt/shell
[root@base shell]# echo '$PWD'
$PWD
[root@base shell]# echo `$PWD`
bash: /opt/shell: Is a directory

运算符

shell中的运算符主要有比较运算符(用于整数比较)、字符串运算符(用于字符串测试)、文件操作运算符(用于文件测试)、逻辑运算符、算术运算符、位运算符、自增自减运算符等。

1、算术运算符

算术运算符指的是加、减、乘、除、余、幂等常见的算术运算,以及加等、减等、乘等、除等、余等复合算术运算。要特别注意的是,shell只支持整数计算,也就是说所有可能产生小数的运算都会舍去小数部分。

/ 除法
% 取模-返回除法的余数
余数是整数除法中被除数未被除尽部分,余数的取值范围为0-除数(不包括除数)的整数
eg:27%6 商数为4,余数为3
若被除数小于除数,则商为0,余数为被除数本身。

Bash shell 的算术运算有四种方式:

1:使用 expr 外部程式

[root@shell ~]# a=`expr 4 + 5`
[root@shell ~]# echo $a
9

PS:注意! ‘4’ ‘+’ ‘5’ 这三者之间要有空格

[root@shell ~]# a=`expr 4+5`
[root@shell ~]# echo $a
4+5
[root@shell ~]# a=`expr 4 * 5`
expr: 语法错误
[root@shell ~]# a=`expr 4 \* 5`
[root@shell ~]# echo $a
20

2:使用 $(( ))

[root@shell ~]# a=$((4 + 5))
[root@shell ~]# echo $a
9

3:使用 $[ ]

[root@shell ~]# a=$[4 + 5]
[root@shell ~]# echo $a
9

4:使用let 命令

[root@shell ~]# m=2
[root@shell ~]# n=3
[root@shell ~]# let a=m+n
[root@shell ~]# echo $a

5: 总结

总结:4种写法的算术运算,例子以数字2、3举例

PS: let命令可以直接用变量名,并且支持变量名和具体数值之间的各种运算。

[root@shell ~]# cat yunsuan.sh
#!/bin/bash
jia=`expr $1 + $2`
echo "参数相加 : $jia"
jian=`expr $1 - $2`
echo "参数相减 :$jian"
cheng=`expr $1 \* $2`
echo "参数相乘 :$cheng"
chu=`expr $1 / $2`
echo "参数相除:$chu"
qumo=`expr $1 % $2`
echo "参数取模:$qumo"
if [ $1 == $2 ]
thenecho "两个参数相等"
fi
if [ $1 != $2 ]
thenecho "两个参数不相等"
fi

PS: 乘号(*)前边必须加反斜杠()才能实现乘法运算;
if…then…fi 是条件语句,后续将会讲解。

2、与运算、或运算、亦或运算

在说这个之前,先来说一下10进制转2进制。
将一个十进制数除以二,得到的商再除以二,依此类推直到商等于一或零时为止,倒取除得的余数,即换算为二进制数的结果。只需记住要点:除二取余,倒序排列。

二进制转十进制的转换原理:从二进制的右边第一个数开始,每一个乘以2
的n次方,n从0开始,每次递增1。然后得出来的每个数相加即是十进制
数。

与运算:&(并且)and

0 false
假 1 true 真
0&0=0
0&1=0
1&0=0
1&1=1

或运算:| 或者 or

0|0=0
0|1=1
1|0=1
1|1=1

XOR运算:^ 异或

(一山不容二虎,除非一公一母。。。)

[root@shell ~]# let "c=100&125"
[root@shell ~]# echo $c
100
[root@shell ~]# let "c=100|125"
[root@shell ~]# echo $c
125
[root@shell ~]# let "c=100^125"
[root@shell ~]# echo $c
25

短路与 && 逻辑与

0&&0=0
0&&1=0
1&&0=0
1&&1=1
如果是命令: cmd1 && cmd2
如果cmd1为假,cmd2不需要执行。反之cmd1为真,需要执行 cmd2
拿到命令里来说: 前边执行成功,后边的才会执行

短路或 || 逻辑或

0||0=0
0||1=1
1||0=1
1||1=1
cmd1 || cmd2
如果cmd1为真,cmd2不需要执行。反之cmd1为假,需要执行cmd2.

那么这个时候就来想一下,如果我想要添加用户,想要现,如果没有此用户,我就添加,应该怎么来实现。

[root@shell ~]# id user1 && useradd user1
id: user1: no such user
[root@shell ~]# id user1 && useradd user1
id: user1: no such user
[root@shell ~]# id user1 || useradd user1
id: user1: no such user
[root@shell ~]# id user1 || useradd user1
uid=1000(user1) gid=1000(user1) groups=1000(user1)

那么再来想一下,修改用户user2的密码,如果有用户接修改,如果没有先添加用户

[root@base ~]# echo 123.com | passwd --stdin user2 ||
useradd user2
passwd: Unknown user name 'user2'.
[root@base ~]# echo 123.com | passwd --stdin user2 ||
useradd user2
Changing password for user user2.
passwd: all authentication tokens updated successfully.

练习:
定义两个数组groupA和 groupB,groupA中的元素分别为:zhangsan lisi
wangwu zhaoliu,
groupB中的元素分别为:gangtiexia zhizhuxia heiguafu lvjuren meidui。写出一个脚本。
判断两个参数是否相等,如果相等则打印出“元素数量相等”,如果不相等则
打印“元素数量不相等”
groupA\groupB\元素的数量相加等于多少
groupA\groupB\元素的数量相减等于多少
groupA\groupB\元素的数量相乘等于多少
groupA\groupB\元素的数量相除等于多少
groupA\groupB\元素的数量取模是多少
groupA\groupB\元素的数量等于多少

[root@base ~]# cat jiaoben1.sh
#!/bin/bash
if [ $1 == $2 ]
thenecho "两个参数相等"
fi
if [ $1 != $2 ]
thenecho "两个参数不相等"
fi
xiangjia=`expr $1 + $2`
echo "参数相加:$xiangjia"
xiangjian=`expr $1 - $2`
echo "参数相减:$xiangjian"
xiangcheng=`expr $1 \* $2`
echo "参数想乘:$xiangcheng"
xiangchu=`expr $1 / $2`
echo "参数相除:$xiangchu"
qumo=`expr $1 % $2`
echo "参数取模:$qumo"
[root@base ~]# groupA=(zhangsan lisi wangwu zhaoliu)
[root@base ~]# groupB=(gangtiexia zhizhuxia heiguafu
lvjuren meidui)
[root@base ~]# a=`echo ${#groupA[@]}`
[root@base ~]# b=`echo ${#groupB[@]}`
[root@base ~]# bash jiaoben1.sh $a $b
两个参数不相等
参数相加:9
参数相减:-1
参数想乘:20
参数相除:0
参数取模:4

关系运算符

关系运算符只支持数字,不支持字符串,除非字符串的值是数字。

-eq 检测两个数是否相等,相等返回 true。 [ $a -eq $b ] 返回 false。
-ne 检测两个数是否不相等,不相等返回 true。 [ $a -ne $b ] 返回 true。
-gt 检测左边的数是否大于右边的,如果是,则返回 true。 [ $a -gt $b ] 返回 false。
-lt 检测左边的数是否小于右边的,如果是,则返回 true。 [ $a -lt $b ] 返回 true。
-ge 检测左边的数是否大于等于右边的,如果是,则返回 true。 [ $a -ge $b ] 返回 false。
-le 检测左边的数是否小于等于右边的,如果是,则返回 true。 [ $a-le $b ] 返回 true。
PS: eq: equql平等的,相等的 gt: greater较大的,大于 lt: less then 小于
gt: greater较大的,大于
lt: less then 小于

举例脚本:

[root@base ~]# groupB=(gangtiexia zhizhuxia heiguafu
lvjuren meidui)
[root@base ~]# a=`echo ${#groupA[@]}`
[root@base ~]# b=`echo ${#groupB[@]}`
[root@base ~]# bash jiaoben1.sh $a $b
两个参数不相等
参数相加:9
参数相减:-1
参数想乘:20
参数相除:0
参数取模:4
#!/bin/bash
if [ $1 -eq $2 ]
thenecho "$1 -eq $2 : $1 等于 $2"
elseecho "$1 -eq $2 : $1 不等于 $2"
fi
if [ $1 -ne $2 ]
thenecho "$1 -ne $2 : $1 不等于 $2"
elseecho "$1 -ne $2 : $1 等于 $2"
fi
if [ $1 -gt $2 ]
thenecho "$1 -gt $2 : $1 大于 $2"
elseecho "$1 -gt $2 : $1 不大于 $2"
fi
if [ $1 -lt $2 ]
thenecho "$1 -lt $2 : $1 小于 $2"
elseecho "$1 -lt $2 : $1 不小于 $2"
fi
if [ $1 -ge $2 ]
thenecho "$1 -ge $2 : $1 大于或等于 $2"
elseecho "$1 -ge $2 : $1 小于 $2"
fi
if [ $1 -le $2 ]
thenecho "$1 -le $2 : $1 小于或等于 $2"
elseecho "$1 -le $2 : $1 大于 $2"
fi

练习写一个脚本:
判断两个参数的大小,要求:
如果参数1大于参数2,那么两数相减,并输出结果值“因为参数1大于参数2,所以两数相减,结果值为:
如果参数1等于参数2,那么两数想乘,并输出结果值“因为参数1等于参数2,所以两数相乘,结果值为:
如果参数1小于参数2,那么两数想加,并输出结果值“因为参数1小于参数2,所以两数相加,结果值为:

#!/bin/bash
if [ $1 -gt $2 ]
thenecho "参数$1 大于 $2 ,所以两数相减等于:`expr $1 -
$2`"
fi
if [ $1 -eq $2 ]
thenecho "参数$1 等于 $2,所以两数相乘等于:`expr $1 \*
$2`"
fi
if [ $1 -lt $2 ]
thenecho "参数$1 小于 $2 ,所以两数相加等于:`expr $1 +
$2`"
fi

Linux shell脚本1相关推荐

  1. 学习笔记之Linux Shell脚本教程:30分钟玩转Shell脚本编程

    Linux Shell脚本教程:30分钟玩转Shell脚本编程 http://c.biancheng.net/cpp/shell/ 转载于:https://www.cnblogs.com/pegasu ...

  2. Linux shell脚本基础学习

    Linux shell脚本基础学习这里我们先来第一讲,介绍shell的语法基础,开头.注释.变量和 环境变量,向大家做一个基础的介绍,虽然不涉及具体东西,但是打好基础是以后学习轻松地前提. 1. Li ...

  3. linux 检查权限,检查目录下 文件的权限-linux shell脚本,

    检查目录下 文件的权限-linux shell脚本, #!/bin/bash #History: #2019/07/23    Fsq #This Program will check Permiss ...

  4. Linux shell脚本数值计算个人心得

    Linux shell脚本数值计算个人心得 本篇博客为,个人对与bash数值计算的一些心得与用法. Bash对于数值是没有明确定义的,在shell里面所有的数值都默认为字符串,并不是单纯的数值. 比如 ...

  5. linux运维实战练习及linux shell脚本、awk、sed工具命令学习总结

    一.linux shell 脚本 1.描述shell程序的运行原理(可附带必要的图形说明): Linux系统的shell作为操纵系统的外壳,为用户提供使用操纵系统的接口.它是命令语言.命令解释程序及程 ...

  6. linux shell脚本字符串连接符,学习Linux shell脚本中连接字符串的方法

    这篇文章主要介绍了Linux shell脚本中连接字符串的方法,如果想要在变量后面添加一个字符,可以用一下方法: 代码如下: $value1=home $value2=${value1}"= ...

  7. linux下实用小脚本,十个增加 Linux Shell 脚本趣味的小工具

    很多人误以为shell脚本只能在命令行下使用.其实shell也可以调用一些GUI组件,例如菜单,警告框,进度条等等.你可以控制最终的输出,光标位置还有各种输出效果.下面我将介绍一些工具,帮助你创建强大 ...

  8. Linux Shell脚本入门--wget 命令用法详解

    Linux Shell脚本入门--wget 命令用法详解 wget是在Linux下开发的开放源代码的软件,作者是Hrvoje Niksic,后来被移植到包括Windows在内的各个平台上.它有以下功能 ...

  9. Linux shell脚本基础学习详细介绍(完整版)一

    Linux shell脚本基础学习这里我们先来第一讲,介绍shell的语法基础,开头.注释.变量和 环境变量,向大家做一个基础的介绍,虽然不涉及具体东西,但是打好基础是以后学习轻松地前提. 1. Li ...

  10. linux sh脚本 while,Linux shell脚本使用while循环执行ssh的注意事项

    原标题:Linux shell脚本使用while循环执行ssh的注意事项 如果要使用ssh批量登录到其它系统上操作时,我们会采用循环的方式去处理,那么这里存在一个巨大坑,你必须要小心了. 一.场景还原 ...

最新文章

  1. 解决IE不支持Data.parse()的问题
  2. CSS3 选择器总结(表格版)
  3. 系统脆弱性检测 (sysytem vulnerability detection) 的研究分类
  4. c语言括号匹配输出个数字,C程序括号匹配检查(带详细注释)
  5. Python入门经典学习1-乳腺癌分类问题
  6. TOC约束理论AUTOCAD技巧
  7. 把html模板vue框架,vue框架搭建个人博客网站模板
  8. “在禁用 UAC 时,无法激活此应用”问题解决
  9. 对拳击“海盗式”打法特点的剖析
  10. 开虚拟机服务器cpu百分之百应该管,为何我在虚拟机里开游戏CPU使用率90--100
  11. 一人行,必有我师焉 2020.11.22日记
  12. mysql课设体会_课程设计心得体会8篇
  13. Unity3d组合键
  14. 网吧服务器点歌系统,网吧点歌系统(网吧点歌曲软件)
  15. 机器人运动控制算法专栏介绍
  16. hutool 合并单元格
  17. 套筒机械加工工艺规程制订(论文+DWG图纸+工序卡)
  18. 运维监控之HP存储监控及hp存储系列产品
  19. 手撕神经网络(2)—— 将基本组件搭建成躯干
  20. 我是如何从 0 到 1 打造一款百万用户 App 的?

热门文章

  1. Hadoop介绍以及安装使用入门
  2. 01.数据库之清理表数据
  3. 在二维码上添加图片主题(支持链接跳转)
  4. IJCAI 阿里论文 | 基于改进注意力循环控制门,品牌个性化排序升级系统来了
  5. 王衠:爱游戏电视游戏平台将实现宽带支付
  6. AR眼镜走向独立,从一个配件开始
  7. 厚屁股的 240Hz 次旗舰 — ROG 枪神 3 评测
  8. 变种 背包问题_算法题:背包问题
  9. (素材源码)猫猫学IOS(十七)UI之纯代码自定义Cell实现新浪微博UI
  10. 女生学计算机真的难吗,女生想学计算机科学与技术,怕很难学懂,这门学科是不是特别难?女生学到底好不好?...