Shell编程(一)

目录

 一、Shell简介

1.1 Shell介绍

1.1.1 Shell 的种类

1.1.2 shell脚本

1.2 路径介绍(环境变量配置相关) 

二、Shell环境变量

2.1 前提

2.2 bashrc与profile的区别

三、常用命令

 快捷键

前提:

3.1 head

3.1.1 -n

3.1.2 -c

3.1.3  打印中间行的数据(面试经常问)

3.2 tail

3.2.1 -c

3.2.2 -n

3.2.3 -f (常用)

3.3 cut

3.3.1 -f 指定获取的列号 

3.3.2 -d 指定分割符

3.4 sort 对文本进行排序

3.4.1 默认排序规则:

3.4.2 -n 按照数字大小排序

3.4.3 指定某一列进行排序

3.4.5 倒序排序 -r

3.5 uniq 去重

3.6 wc(word count) 计算文本数量

3.7 echo 打印内容

四、变量

4.1 分类

4.2 定义变量(本地变量)

4.3 全局变量(临时)

3.3.1 将本地变量直接转换为全局变量:export 本地变量

4.3.2 创建全局变量:export 变量名=变量值

3.3.3 查看有哪些全局变量

4.4 全局变量(永久)

4.5 使用变量

4.5 内置变量

四、数值运算

4.1 支持的运算

4.2 方式一 $((算数表达式)) (常用)

4.3 方式二 `expr 算数表达式`(不常用)

4.3 方式三 bc交互式

五、条件表达式

5.1 返回值

5.2 文件表达式

5.3 数值操作符

5.4 字符串比较

5.5 逻辑表达式

六、shell脚本格式

6.1 格式要求

6.2 shell 脚本应用场景

6.3 shell脚本执行方式


 一、Shell简介

1.1 Shell介绍

Shell

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

Shell 编程跟 python 编程一样,只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就可以了。

1.1.1 Shell 的种类

Shell 是一个程序,一般都是放在/bin或者/user/bin目录下,当前 Linux 系统可用的 Shell 都记录在/etc/shells文件中,可以使用 cat 命令查看它;

cat /etc/shells
[root@ecs-39233 ~]# cat /etc/shells
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash

Linux 的 Shell 种类众多,常见的有:

Bourne Shell(/usr/bin/sh或/bin/sh)
Bourne Again Shell(/bin/bash)
C Shell(/usr/bin/csh)
K Shell(/usr/bin/ksh)
Shell for Root(/sbin/sh)

/bin/sh #是bash的一个快捷方式

/bin/bash #bash是大多数Linux默认的shell,包含的功能几乎可以涵盖shell所有的功能

/sbin/nologin #表示非交互,不能登录操作系统

/bin/dash #小巧,高效,功能相比少一些

/bin/csh #具有C语言风格的一种shell,具有许多特性,但也有一些缺陷

/bin/tcsh #是csh的增强版,完全兼容csh

由于易用和免费,Bash (Bourne Again Shell)在日常工作中被广泛使用。同时,Bash 也是大多数Linux 系统默认的 Shell。

在一般情况下,并不区分 Bourne Shell 和 Bourne Again Shell,所以,像 #!/bin/sh,它同样也可以改为 #!/bin/bash。

查看当前 Linux 的默认 Shell,那么可以输出 SHELL 环境变量:

echo $SHELL
[root@ecs-39233 ~]# echo $SHELL
/bin/bash

交互式shell和非交互式shell

交互式模式:就是shell等待你的输入,并且执行你提交的命令。这种模式被称作交互式是因为shell与用户进行交互。这种模式也是大多数用户非常熟悉的:登录、执行一些命令、签退。当你签退后,shell也终止了。(这种shell中的命令时由用户从键盘交互式地输入的,运行的结果也能够输出到终端显示给用户看。例如我们平常在终端输入的cd命令、vi命令、mv等都属于交互式的)

非交互式模式:在这种模式下,shell不与你进行交互,而是读取存放在文件中的命令,并且执行它们。当它读到文件的结尾,shell也就终止了。(这种shell可能由某些自动化过程启动,不能直接从请求用户的输入,也不能直接输出结果给终端用户看。通常我们写的shell脚本都是非交互式的,通过sh 直接运行该脚本文件)

login shell 与 non-login shell! 重点在于有没有登陆 (login)

loginshell nologinshell_nologin shell_大泥田的博客-CSDN博客

login shell:取得 bash 时需要完整的登陆流程的,就称为 login shell。

non-login shell:取得 bash 接口的方法不需要重复登陆的举动。

1.1.2 shell脚本

Shell 脚本(shell script),是一种为 shell 编写的脚本程序。

业界所说的 shell 通常都是指 shell 脚本,但是要知道,shell 和 shell script 是两个不同的概念。

shell脚本就是将需要执行的命令保存到文本中,按照顺序执行。它是解释型的,意味着不需要编译。

shell脚本的基本写法

1)脚本第一行,#!指定解释器

#! 告诉系统其后路径所指定的程序即是解释此脚本文件的 Shell 程序。

#!/bin/bash 表示使用bash解释器解析

注意: 如果直接将解释器路径写死在脚本里,可能在某些系统就会存在找不到解释器的兼容性问题,所以可以使用: #!/bin/env 解释器

2)脚本第二部分,注释(#号)说明,对脚本的基本信息进行描述【可选】

3)脚本第三部分,脚本要实现的具体代码内容

如:

#!/bin/env bash

# 以下内容是对脚本的基本信息的描述

# Name: 名字

# Desc:描述describe

1.2 路径介绍(环境变量配置相关) 

mac与linux配置环境变量的说明_vim ~/.zshrc_做测试的喵酱的博客-CSDN博客

1、“~” :表示主目录,也就是当前登录用户的用户目录。

2、“/” :是指根目录:就是所有目录最顶层的目录

3、“./” :表示当前目录,./ 一般需要和其他文件夹或者文件结合使用,指代当前目录下的东西。

4、“..” :表示上级目录

 具体修改哪个文件,根据系统当前的shell解释器的类型。

看当前设备的shell解析器。

zhaohui@zhaohuideMacBook-Pro ~ % echo $SHELL

/bin/zsh

 zsh 解释器。.zshrc文件是zsh解释器的环境变量配置文件。 

vim ~/.zshrc


[root@ecs-39233 ~]# echo $SHELL
/bin/bash

.bash_profile文件是bash解释器的环境变量配置文件。  

vim ~/.bash_profile
 
 

1、.代表隐藏文件

.bash_profile 表示一个名为.bash_profile的隐藏文件

vi .bash_profile ,就是编辑当前目录的隐藏文件.bash_profile

2、环境变量配置与文件名无关与文件路径无关

我们在配置环境变量后,都要声明一下

source ~/.bash_profile
或者

source .bash_profile


2.1 与文件名无关,只要source声明环境变量就可以了

2.2 与文件路径无关,一台设备上可以有多个目录下的.bash_profile 文件,只要声明了就可以

3、“~” :表示主目录,也就是当前登录用户的用户目录。

比如:我登录用户是chen,~ 代表的就是 /home/chen/

vi ~/.bash_profile
source ~/.bash_profile
表示的就是编辑主目录下的 .bash_profile 文件。

4、建议

为了环境变量的统一,我建议还是使用

vi ~/.bash_profile
source ~/.bash_profile
这样方便统一管理,和寻找。

二、Shell环境变量

一进入 bash 就取得一堆有用的变量,这是因为系统有一些环境设置文件的存在,让 bash 在启动时直接读取这些配置文件,以规划好 bash 的操作环境。

这些配置文件又可以分为全体系统的配置文件以及使用者个人偏好配置文件。

2.1 前提

 交互式shell和非交互式shell

交互式模式:就是shell等待你的输入,并且执行你提交的命令。这种模式被称作交互式是因为shell与用户进行交互。这种模式也是大多数用户非常熟悉的:登录、执行一些命令、签退。当你签退后,shell也终止了。(这种shell中的命令时由用户从键盘交互式地输入的,运行的结果也能够输出到终端显示给用户看。例如我们平常在终端输入的cd命令、vi命令、mv等都属于交互式的)

非交互式模式:在这种模式下,shell不与你进行交互,而是读取存放在文件中的命令,并且执行它们。当它读到文件的结尾,shell也就终止了。(这种shell可能由某些自动化过程启动,不能直接从请求用户的输入,也不能直接输出结果给终端用户看。通常我们写的shell脚本都是非交互式的,通过sh 直接运行该脚本文件)

login shell 与 non-login shell

 重点在于有没有登陆 (login)

loginshell nologinshell_nologin shell_大泥田的博客-CSDN博客

login shell:取得 bash 时需要完整的登陆流程的,就称为 login shell。

non-login shell:取得 bash 接口的方法不需要重复登陆的举动。

2.2 bashrc与profile的区别

bashrc与profile的区别_bashrc和profile区别_Frankie_He的博客-CSDN博客

bashrc与profile都用于保存用户的环境信息,bashrc用于交互式non-loginshell,而profile用于交互式login shell。

login shell

login shell启动时首先读取/etc/profile系统全局配置,然后依次查找/.bash_profile、/.bash_login、~/.profile三个配置文件,并且读取首个找到的并且可读的文件。
login shell退出时读取并执行~/.bash_logout中的命令。 如果配置文件存在但不可读,则会显示错误消息;如果文件不存在,bash将自动搜索下一个文件。

nologin shell
nologin shell在初始化时仅读取~/.bashrc资源文件, 而/.bashrc文件会自动被/.bash_profile或~/.profile加载,因此为了保证login shell和交互式non-login shell得到相同的配置,一般将环境变量定义在~/.bashrc文件中 。

/etc/profile,/etc/bashrc 是系统全局环境变量设定
~/.profile,~/.bashrc用户家目录下的私有环境变量设定

/etc/profile中设定的变量(全局)的可以作用于任何用户,

~/.bashrc等中设定的变量(局部)只能继承/etc/profile中的变量,他们是"父子"关系。

系统中存在许多bashrc和profile文件,下面逐一介绍:

/etc/profile 此文件为系统的每个用户设置环境信息,当第一个用户登录时,该文件被执行. 并从/etc/profile.d目录的配置文件中搜集shell的设置.

/etc/bashrc 为每一个运行bash shell的用户执行此文件.当bash shell被打开时,该文件被读取。有些linux版本中的/etc目录下已经没有了bashrc文件。

~/. profile每个用户都可使用该文件输入专用于自己使用的shell信息,当用户登录时,该文件仅仅执行一次!默认情况下,它设置一些环境变量,然后执行用户的.bashrc文件.

~/.bashrc 该文件包含专用于某个用户的bash shell的bash信息,当该用户登录时以及每次打开新的shell时,该文件被读取。


当登入系统时候获得一个shell进程时,其读取环境设定档有三步
1、首先读入的是全局环境变量设定档/etc/profile,然后根据其内容读取额外的设定的文档,如
/etc/profile.d和/etc/inputrc


2、然后根据不同使用者帐号,去其家目录读取~/.bash_profile,如果这读取不了就读取~/.bash_login,这个也读取不了才会读取
~/.profile,这三个文档设定基本上是一样的,读取有优先关系


3、然后在根据用户帐号读取~/.bashrc
至于~/.profile与~/.bashrc的区别
都具有个性化定制功能
~/.profile可以设定本用户专有的路径,环境变量,等,它只能登入的时候执行一次
~/.bashrc也是某用户专有设定文档,可以设定路径,命令别名,每次shell script的执行都会使用它一次 

mac修改环境变量的两种方式_做测试的喵酱的博客-CSDN博客

mac与linux配置环境变量的说明_vim ~/.zshrc_做测试的喵酱的博客-CSDN博客

三、常用命令

 快捷键

ctrl+a 将光标定位到第一个位

ctrl+e 将光标定位到最后一位

ctrl+l 清屏

前提:

学习命令的使用方式,最好的方式就是查看帮助信息。

xx --help (推荐这种方式)

如查看head命令的使用方式

head --help

想要查看更加详细的帮助文档,使用 man xx 

man head

查看再详细一点的帮助文档,使用 info xx

help帮助信息分析:

head --help

1、主要查看Usage信息。

Usage: head [OPTION]... [FILE]...

 命令中,[]方括号中的信息,是选填的,可加可不加。

2、Print 打印 这个命令的描述

Print the first 10 lines of each FILE to standard output.
With more than one FILE, precede each with a header giving the file name.
With no FILE, or when FILE is -, read standard input.

----------打印每个文件的前10行,打印到标准输出(当前屏幕)

3.1 head

默认获取文件前10行

使用方式:

head miao.sql

查看miao.sql文件的前10行数据。

3.1.1 -n

  -n, --lines=[-]K         print the first K lines instead of the first 10;
                             with the leading '-', print all but the last
                             K lines of each file

(以行为单位)可以指定打印前xx行。

打印miao.sql的前5行数据

head -n 5 miao.sql 

省略n,直接-数字也生效。如下

head -5 miao.sql 

3.1.2 -c

 -c, --bytes=[-]K         print the first K bytes of each file;
                             with the leading '-', print all but the last
                             K bytes of each file

(以字节为单位)打印前xx个字节。

打印cs.sql文件的前3个字节。(一个字符一个字节)

head -c 3 cs.sql 

3.1.3  打印中间行的数据(面试经常问)

需求:打印第9行--15行的数据。

head -n 15 cs.sql | tail -n 6

先取出cs.sql 文件中,前15行的内容 head -n 15 cs.sql

通过管道符|,将上一个命令拿到的结果,在取这个结果中的后6行(9-15行)数据

| tail -n 6

3.2 tail

查看帮忙信息

[root@ecs-39233 chenshuai]# tail --help
Usage: tail [OPTION]... [FILE]...
Print the last 10 lines of each FILE to standard output.
With more than one FILE, precede each with a header giving the file name.
With no FILE, or when FILE is -, read standard input.

Mandatory arguments to long options are mandatory for short options too.
  -c, --bytes=K            output the last K bytes; or use -c +K to output
                             bytes starting with the Kth of each file
  -f, --follow[={name|descriptor}]
                           output appended data as the file grows;
                             an absent option argument means 'descriptor'
  -F                       same as --follow=name --retry
  -n, --lines=K            output the last K lines, instead of the last 10;
                             or use -n +K to output starting with the Kth
      --max-unchanged-stats=N

默认获取文件后10行。

tail cs.sql

默认打印cs.sql文件的最后10行数据 

3.2.1 -c

(以字节为单位)打印最后 x个字节。

举例:

打印最后5个字节

tail -c 5 cs.sql 

3.2.2 -n

(以行为单位)打印最后 x行的内容。

打印最后 x行的内容。

tail -n 5 cs.sql

打印最后5行的内容。 

3.2.3 -f (常用)

动态查看文件数据。

应用场景:在查看日志文件的时候。

tail -f cs.log

3.3 cut

取出文件指定的列。默认以空格或者tab键进行分割(不支持不规则空格)

查看帮助信息 cut --help

[root@ecs-39233 chenshuai]# cut --help
Usage: cut OPTION... [FILE]...
Print selected parts of lines from each FILE to standard output.

Mandatory arguments to long options are mandatory for short options too.
  -b, --bytes=LIST        select only these bytes
  -c, --characters=LIST   select only these characters

Usage: cut OPTION... [FILE]...

OPTION ,没有方括号,为必填项。

常用:

-d 指定分隔符

-f 指定获取的列号

举例:

新建test1文件

vim test1

添加以下内容。(tab键进行分割的)

name    age     address
aaa1    18      beijing
aaa2    20      shanghai
aaa3    22      shenzhen
                      

3.3.1 -f 指定获取的列号 

查看第1列的数据

cut -f 1 test1

查看第2列的数据

cut -f 2 test1

同时打印第1列,第2列的数据。

- 是连续区间

,是取单个的列

方式一

cut -f 1,2 test1

方式二

cut -f 1-2 test1

3.3.2 -d 指定分割符

以/etc/passwd文件为例。查看/etc/passwd

cat /etc/passwd

 该文件是以冒号:进行分割的。

我们要打印(以冒号:分割)第一列的数据

cut -d":" -f1 /etc/passwd

3.4 sort 对文本进行排序

sort对文本进行排序

3.4.1 默认排序规则:

取每一行的第一个字符,按照ASCII 进行排序的。

sort --help

举例

新建sort.txt文件

vim sort.txt

写入内容

1
22
2
12
11
23
3
12
31
32

 对sort.txt文件进行排序

sort srot.txt 

查看排序结果,这里不是按照数字大小排序的。而是取每一行的第一个字符,按照ASCII 进行排序的。

3.4.2 -n 按照数字大小排序

sort -n sort.txt 

3.4.3 指定某一列进行排序

-k 指定某一列进行排序。(列的划分,默认按照空格划分)

-t 指定分隔符

举例:

sort -t":" -k3 /etc/passwd

先按照:进行列的分割。然后取第3列数据进行排序(排序规则ASCII)

按照数值大小排序 -n

sort -t":" -k3 -n /etc/passwd

3.4.5 倒序排序 -r

举例:

按照数值大小,倒序排序

​
sort -t":" -k3 -n /etc/passwd

​

3.5 uniq 去重

uniq 只能对有顺序的文本进行去重。

新建一个文本uniq.txt

1
22
1
2
12
11
23
3
2
12
3
31
32

直接进行去重 uniq uniq.txt

1
22
1
2
12
11
23
3
2
12
3
31
32

发现实际并没有去重。(uniq 只能对有顺序的文本进行去重。)

我们我们要先排序,再去重。(这里按照数字大小排序 sort -n)

sort -n uniq.txt |uniq

3.6 wc(word count) 计算文本数量

wc -l 打印行数

wc -l /etc/passwd

wc -w 打印单词数

wc -w /etc/passwd

wc -c 打印字节数

wc -L 打印最长行的字节数

3.7 echo 打印内容

直接打印值

打印变量

-n 不换行

连续打印两个值,打印结果进行了换成

[root@ecs-39233 ~]# echo 你好; echo 大家好
你好
大家好

-n 打印结果不换行

[root@ecs-39233 ~]# echo -n 你好; echo 大家好
你好大家好

-e 识别转义字符

如:

[root@ecs-39233 ~]# echo "$SHELL \n你好"
/bin/bash \n你好

\n 为换行符,直接打印没有识别出\n,而是直接进行了打印。

使用-e就可以识别打印内容里的换行符。 

[root@ecs-39233 ~]# echo -e "$SHELL \n你好"
/bin/bash 
你好

四、变量

4.1 分类

  • 本地变量
  • 全局变量
  • 内置变量

4.2 定义变量(本地变量)

注意,

1、我们这里在命令行里定义的是本地变量,不可以在不同的终端中访问,也不能在shell脚本中使用这些变量

2、定义变量时,等号前边不允许有空格。key="value"

方式一 变量名=变量值

变量值必须是一个整体,中间没有特殊字符,等号两侧不能有空格。

方式二 变量名=‘变量值’

单引号与双引号有本质区别

变量值,输入的什么就是什么,不会解析里面的数据信息。

比如,我先定义一个变量 name=李四 ,再定一个变量 x='$name 18'

打印x结果为 x='$name 18'

方式三 变量名=“变量值”

双引号,可以解析双引号内的变量。

举例,定一个变量y="$name 20"

方式四 将linux命令运行结果赋值给一个变量

实现功能:将linux命令运行结果赋值给一个变量

变量名=$(linux命令)

举例

date为linux系统命令,打印当前系统的时间。

我想要将date这个命令的执行结果封装为我自定义的一个变量。

使用 变量名=$(linux命令),my_data=$(date)

变量名=`linux命令`

注意,这里是反引号,不是单引号。(键盘左上角的)

实现功能:将linux命令运行结果赋值给一个变量

撤销变量:unset 变量

4.3 全局变量(临时)

全局变量(临时),只能在当前shell窗口中,访问。新开一个shell窗口,访问不到。

3.3.1 将本地变量直接转换为全局变量:export 本地变量

举例:

新建本地变量

 name=张三

新建print.sh文件

echo $name

运行sh文件

sh print.sh

查看当前打印结果为空。

将name转换为全局变量 export

export name 

再次执行pint.sh文件

sh print.sh

打印结果为:张三 

4.3.2 创建全局变量:export 变量名=变量值

举例

export username=李四

3.3.3 查看有哪些全局变量

env

4.4 全局变量(永久)

全局变量(永久)可以在其他shell窗口中访问。

将(永久保存的)变量写到下面三个的文件中

vim ~/.bashrc
vim ~/.bash_profile
vim /etc/profile

export 变量名=变量值

设置完变量后,通过source命令使变量生效。 

source ~/.bashrc
source ~/.bash_profile
source /etc/profile

4.5 使用变量

方式一

echo $name

方式二 

echo "$name"

方式三

echo "{name}"

在命令行中,使用变量时,一般使用方式一

在脚本中,调用某个变量时,一般使用方式二。加双引号的(方式一在脚本中,当变量的值有空格时,可能会报错)

4.5 内置变量

linux 系统自带的变量。以下是常用的内置变量

1、变量:$?  上一条命令的直接结果 (重点)

上一条命令,执行成功,echo $? 打印结果为0

举例:

[root@ecs-39233 ~]# date
Mon Apr 17 10:37:59 CST 2023
[root@ecs-39233 ~]# 
[root@ecs-39233 ~]# echo $?
0

上一条命令,执行失败,echo $? 打印结果为非0

[root@ecs-39233 ~]# ls /xxx
ls: cannot access /xxx: No such file or directory
[root@ecs-39233 ~]# echo $?
2
符号 作用
$0 获取当前执行的shell脚本文件名,包括脚本路径
$n

获取当前执行的shell脚本的第n个参数值。n=1.2...9

如果n大于9就要用大括号括起来${10}

$# 获取当前shell命令中参数的总个数
$? 获取执行上一个指令的返回值(0为成功,非0为执行失败)
$* 这个变量代表命令行中所有的参数,$*把所有的参数看成一个整体
$@ 这个变量也代表命令行中所有的参数,不过$@把每个参数区分对待

举例:

新建一个shell脚本。

vim  test.sh 
echo "当前脚本的名称 $0"
echo "脚本接受的第一个参数 $1"
echo "脚本接收的第10个参数 ${10}"
echo "脚本接收的所有参数:$@"
echo "脚本接收的参数总个数: $#"

在shell终端中,执行 test.sh 脚本

sh test.sh a b c d e f g h i j k l m n
[root@ecs-39233 ~]# sh test.sh a b c d e f g h i j k l m n
当前脚本的名称 test.sh
脚本接受的第一个参数 a
脚本接收的第10个参数 j
脚本接收的所有参数:a b c d e f g h i j k l m n
脚本接收的参数总个数: 14

注意,执行shell脚本,输入参数时。多个参数直接用空格分割就行(没有规定两个参数之间具体用几个空格分割,用几个空格都行)

脚本与参数之间,也是用空格分割。

四、数值运算

4.1 支持的运算

加减乘 整除 取余

+ - * / %

小于 小于等于 大于 大于等于 

< <= > >=

等于 不等于

= !=

4.2 方式一 $((算数表达式)) (常用)

使用方式:

$((算数表达式))

举例 

[root@ecs-39233 ~]# a=1
[root@ecs-39233 ~]# b=2
[root@ecs-39233 ~]# c=3
[root@ecs-39233 ~]# echo $(($a+$b + $c))
6

注意:

表达式中,$(($a+$b + $c)) 可以有空格,也可以没有空格。

也可以将运算结果赋值给一个变量

[root@ecs-39233 ~]# res=$(($a+$b))
[root@ecs-39233 ~]# echo $res
3

算数运算总的变量可以不加$

[root@ecs-39233 ~]# echo $((a+b))
3

 小于 小于等于 大于 大于等于 

< <= > >=

比较运算,结果成立为1。不成立为0。

[root@ecs-39233 ~]# echo $((2>3))
0
[root@ecs-39233 ~]# echo $((2>1))
1

4.3 方式二 `expr 算数表达式`(不常用)

`expr 算数表达式`

这里使用的是反引号 ``

举例

[root@ecs-39233 ~]# res=`expr $a+$b`
[root@ecs-39233 ~]# echo $res
1+2

 注意,expr方式,变量前的$是必须加的。

大于号>在Linux中,有特殊的含义。是重定向符号,在expr中,想要使用>,必须转义。

举例:

>未转义的情况

[root@ecs-39233 ~]# res=`expr 2>3`
[root@ecs-39233 ~]# echo $res

[root@ecs-39233 ~]# 

>需要转义

[root@ecs-39233 ~]# res=`expr 2 \> 3`
[root@ecs-39233 ~]# echo $res
0
[root@ecs-39233 ~]# 

注意,参数之间要有空格(2 与 > 之间要有空格)

4.3 方式三 bc交互式

进入bc

bc
[root@ecs-39233 ~]# bc
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'. 

在bc中,可以直接输入运算

1+2
3
5/2
2

/为整除,除法想要获取小数点,需要先设置scale

举例:10/3,保留2位小数

scale=2
10/3
3.33

退出bc交互

quit

shell脚本中很常见的算数运算方式:

[root@ecs-39233 ~]# echo "scale=2; 10 / 3" |bc
3.33

scale 设置小数点位数

多个命令,用分号;分割

将命令通过管道符|重定向到bc中运算。

五、条件表达式

条件表达式,三种方式。

方式一

test 条件表达式

方式二 方括号

[ 条件表达式 ]

注意,方括号的首尾都要有一个空格,不然报错。 

方式三

 [[ 条件表达式 ]]

查看test详细使用方法

man test 

5.1 返回值

条件成立,返回0

条件不成立,返回1

5.2 文件表达式

 查看test详细使用方法

man test 

按照文件权限进行判断:

  1. -r (有读的权限)
  2. -w (有写的权限)
  3. -x(有执行的权限)(常用)

按照文件类型进行判断: 

  1. -f(文件存在并且是一个常规文件)
  2. -e(文件存在)
  3. -d(文件存在并是一个目录)

举例

-f 判断输入内容是否是一个文件

[root@ecs-39233 ~]# ls /etc/passwd
/etc/passwd
[root@ecs-39233 ~]# test -f /etc/passwd
[root@ecs-39233 ~]# echo $?
0
[root@ecs-39233 ~]# test -f /etc/xxx; echo $?
1

使用方括号

[root@ecs-39233 ~]# [ -f /etc/passwd ]
[root@ecs-39233 ~]# echo $?
0

注意,方括号的首尾都要有一个空格,不然报错。 

[root@ecs-39233 ~]# [ -f /etc/passwd ]; echo $? 
0

-d 判断一个路径是否为目录

[root@ecs-39233 ~]# test -d /etc/passwd; echo $?
1
[root@ecs-39233 ~]# test -d /etc; echo $?
0

-x 判断一个文件,是否有可执行的权限。

举例,新建一个 miao.sh文件

vim miao.sh

任意输入内容,然后保存退出。

查看文件权限

ll miao.sh
[root@ecs-39233 chenshuai]# ll miao.sh 
-rw-r--r-- 1 root root 445 Apr 17 15:15 miao.sh

miao.sh 没有可执行的权限。

[root@ecs-39233 chenshuai]# test -x miao.sh; echo $?
1

 miao.sh 没有可执行的权限。

修改miao.sh 权限,增加可执行权限

chmod +x miao.sh 

再次查看miao.sh 是否有可执行权限

[root@ecs-39233 chenshuai]# test -x miao.sh; echo $?
0

5.3 数值操作符

x -eq y 相等

x -gt y 大于

x -lt y 小于

x -ne y 不等于 

举例:

定义变量

[root@ecs-39233 chenshuai]# a=5
[root@ecs-39233 chenshuai]# b=6
[root@ecs-39233 chenshuai]# c=5

相等判断

[root@ecs-39233 chenshuai]# test $a -eq $b; echo $?
1
[root@ecs-39233 chenshuai]# test $a -eq $c; echo $?
0

不相等判断

[root@ecs-39233 chenshuai]# test $a -ne $b; echo $?
0

5.4 字符串比较

判断str1 与str2 字符串内容一致

str1 == str2 

 判断str1 与str2 字符串内容不一致

str1 != str2 

字符串长度判断

-z 判断字符串是长度是否为0,长度为0成立时,结果为0

-n 判断字符串是长度是否不为0,长度不为0成立时,结果为0

举例:

[root@ecs-39233 chenshuai]# str1='abc'
[root@ecs-39233 chenshuai]# str2='abc'
[root@ecs-39233 chenshuai]# 
[root@ecs-39233 chenshuai]# test $str1==$str2; echo $?
0

在字符串的条件运算当中,字符串的变量,尽量用双引号包起来(如果字符串的值中,有空格,且使用变量的时候没有用双引号引起来,会报错)

[root@ecs-39233 chenshuai]# test "$str1"=="$str2"; echo $?
0

报错举例:

定义带空格的字符串变量

str3='ab c'

[root@ecs-39233 chenshuai]# test $str1==$str3; echo $?
-bash: test: abc==ab: unary operator expected
2

判断相等时,报错。变量要用引号引起来。

字符串长度判断

-z 判断字符串是长度是否为0,长度为0成立时,结果为0

-n 判断字符串是长度是否不为0,长度不为0成立时,结果为0

先定义长度为0的变量str4

str4=""

判断str4的长度是否为0。 -z

[root@ecs-39233 chenshuai]# test -z "$str4"; echo $?
0
[root@ecs-39233 chenshuai]# [ -z "${str4}" ]; echo $?
0

注意,方括号首尾要有空格。

判断str4的长度,是否为非0

[root@ecs-39233 chenshuai]# [ -n "${str4}" ]; echo $?
1
[root@ecs-39233 chenshuai]# test -n "$str4"; echo $?
1

5.5 逻辑表达式

命令与&& 和 命令或 ||

-a 条件1 与条件2 同时成立(与)

-o 条件1 与条件2 至少有1个成立(或)

命令与&& ,条件为true时,执行命令与&&后面的表达式

命令或 ||,,条件为false时,执行命令或||后面的表达式

举例:

定义变量

username=张三

 逻辑表达式

[root@ecs-39233 chenshuai]# [ "${username}" == "张三" ] && echo "成功" || echo "失败"
成功
[root@ecs-39233 chenshuai]# [ "${username}" == "李四" ] && echo "成功" || echo "失败"
失败
[root@ecs-39233 chenshuai]# test "${username}" == "李四" && echo "成功" || echo "失败"
失败
[root@ecs-39233 chenshuai]# test "${username}" == "张三" && echo "成功" || echo "失败"
成功

定义 score=50,与60做比较 (-gt 大于),score不大于60时,输出 不及格

[root@ecs-39233 chenshuai]# score=50
[root@ecs-39233 chenshuai]# test "$score" -gt 60 && echo "及格" || echo "不及格"
不及格

 定义score=70,与60做比较 (-gt 大于),score大于60时,输出 及格

[root@ecs-39233 chenshuai]# score=70
[root@ecs-39233 chenshuai]# test "$score" -gt 60 && echo "及格" || echo "不及格"
及格

条件1 与条件2 同时成立 (与),最终结果为真

条件1 -a 条件2 

天条1 或条件2 其中只要有一个成立(或),最终结果为真

条件1 -0 条件2 

 举例:

场景:当username=zhangsan 并且 password=123456时,登录成功,否则登录失败。

需要条件1与条件2同时成立才可以,这里用 与 -a

设置变量

[root@ecs-39233 chenshuai]# username=zhangsan
[root@ecs-39233 chenshuai]# password=123456

进行条件判断

[root@ecs-39233 chenshuai]# test "$username" == "zhangsan" -a "$password" == "123456" && echo "登录成功" || echo "登录失败"
登录成功

设置变量

[root@ecs-39233 chenshuai]# username=lisi

进行条件判断

[root@ecs-39233 chenshuai]# test "$username" == "zhangsan" -a "$password" == "123456" && echo "登录成功" || echo "登录失败"
登录失败

六、shell脚本格式

6.1 格式要求

1、脚本名称命名

  • 脚本名称命名,尽量要做到见名知意,看到脚本名称,就知道这个脚本是做什么的。
  • 名称不要有中文
  • 不能以数字开头 

2、在文件首行指定执行shell的程序以及相关说明

#!/bin/bash
#Author: miaojiang
#Date: 2023-04-17

脚本以#!/bin/bash开头,指定执行shell的程序。

#! 有特殊含义

# 代表单行注释

多行注释

:<<! 
注释内容 
!

3、脚本名称,最好加一个.sh 后缀 (如test.sh,当然不加也不影响运行)

4、脚本中,默认缩紧4个空格

5、脚本执行失败时,使用exit 返回非零值,来退出程序。

6.2 shell 脚本应用场景

在linux服务器部署Django项目_linux部署django项目_做测试的喵酱的博客-CSDN博客

部署运行环境。

举例,我想要在Linux上部署python3环境。如果手动去安装,需要很长的流程,

但是我可以把这些命令写到shell脚本中,这样就实现了一键安装python环境,且这个脚本可以重复使用。

编写shell脚本,installPython.sh

#!/bin/bash
/bin/rm -fr /usr/local/python3
wget https://ftp.openssl.org/source/old/1.1.1/openssl-1.1.1j.tar.gz --no-check-certificate
tar xf openssl-1.1.1j.tar.gz
cd openssl-1.1.1j
./config --prefix=/usr/local/openssl-1.1.1j 
make && make install
echo "/usr/local/openssl-1.1.1j/lib/" >/etc/ld.so.conf.d/openssl.conf
ldconfig
 
yum -y install libffi-devel
yum -y install zlib
yum -y install zlib-devel
wget https://www.python.org/ftp/python/3.7.0/Python-3.7.0.tgz
tar -zxvf Python-3.7.0.tgz
cd Python-3.7.0
./configure prefix=/usr/local/python3 --with-openssl=/usr/local/openssl-1.1.1j
make && make install
/usr/local/python3/bin/python3 -V
cd /opt/
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
/usr/local/python3/bin/python3 /opt/get-pip.py
 
 
/usr/local/python3/bin/pip3 install -i https://mirrors.aliyun.com/pypi/simple/ pyaml==19.12.0
/usr/local/python3/bin/pip3 install -i https://mirrors.aliyun.com/pypi/simple/ pycparser==2.19
/usr/local/python3/bin/pip3 install -i https://mirrors.aliyun.com/pypi/simple/ PyGithub==1.45
/usr/local/python3/bin/pip3 install -i https://mirrors.aliyun.com/pypi/simple/ PyJWT==1.7.1
/usr/local/python3/bin/pip3 install -i https://mirrors.aliyun.com/pypi/simple/ pymongo==3.10.1
/usr/local/python3/bin/pip3 install -i https://mirrors.aliyun.com/pypi/simple/ PyMySQL==0.9.3
/usr/local/python3/bin/pip3 install -i https://mirrors.aliyun.com/pypi/simple/ smmap2==2.0.5

 注意把python依赖包换成自己所需要的。

执行shell脚本

sh installPython.sh

6.3 shell脚本执行方式

shell脚本执行方式很多。

新建一个sh脚本 miao_test.sh

vim miao_test.sh

添加描述,和命令

#!/bin/bash
# author: miaojiang
# date: 2023-04-17

echo $PWD
echo $HOME

执行方式一  bash xx.sh     sh xx.sh

[root@ecs-39233 chenshuai]# bash miao_test.sh 
/chenshuai
/root
[root@ecs-39233 chenshuai]# sh miao_test.sh 
/chenshuai
/root

执行方式二 给脚本添加可执行权限

给miao_test.sh 文件,所有的用户组,添加可执行权限。

查看miao_test.sh文件的权限

[root@ecs-39233 chenshuai]# ll miao_test.sh 
-rw-r--r-- 1 root root 73 Apr 17 17:42 miao_test.sh

所有用户组,是没有可执行权限的。

给miao_test.sh 文件,所有的用户组,添加可执行权限。

chmod +x miao_test.sh

再次查看miao_test.sh文件的权限,所有用户组,有可执行的权限

[root@ecs-39233 chenshuai]# ll miao_test.sh 
-rwxr-xr-x 1 root root 73 Apr 17 17:42 miao_test.sh

在命令行中,运行miao_test.sh文件

./miao_test.sh
[root@ecs-39233 chenshuai]# ./miao_test.sh
/chenshuai
/root

执行方式三 source xx.sh

[root@ecs-39233 chenshuai]# source miao_test.sh 
/chenshuai
/root

执行方式四 调试模式 bash -x xx.sh

运行shell脚本的调试模式,可以打印每一步的操作。

[root@ecs-39233 chenshuai]# bash -x miao_test.sh 
+ echo /chenshuai
/chenshuai
+ echo /root
/root

在调试脚本的时候,一般使用这个命令。

执行方式五 配置环境变量,将脚本当成一条命令去执行

1、先配置环境变量。将一个目录配置到环境变量PATH里。这个目录里的shell脚本,都可以当作一条命令去执行。

2、在终端中直接运行shell脚本 ,将脚本当成一条命令去执行

比如在启动jmeter时,我们先配置了jmeter 环境变量,然后直接在终端中输入jmeter就可以启动jmeter了。

linux在执行shell脚本命令时,会先去搜索这个shell脚本。

搜索脚本的路径,都在path变量中。

查看path变量(环境变量)

echo $PATH
[root@ecs-39233 ~]# echo $PATH
/usr/local/apache-jmeter-5.5/bin:/usr/local/apache-jmeter-5.5/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/java/jdk-18.0.1.1/bin:/root/java/jdk-18.0.1.1/bin:/root/bin:/root/bin

环境变量里面的路径,多个路径之间使用冒号:进行分割的。

当我在终端运行jmeter时,先去/usr/local/apache-jmeter-5.5/bin 中,寻找jmeter脚本。

如果在PATH所有的路径中都没找到,就会报not found

如,输入 xxx

[root@ecs-39233 ~]# xxx
-bash: xxx: command not found

查看系统自带命令的路径。

如,在终端中,直接执行 ls是可以的。

[root@ecs-39233 ~]# ls

查看ls命令的路径

[root@ecs-39233 ~]# which ls
alias ls='ls --color=auto'
	/usr/bin/ls

ls命令在/usr/bin目录下。 /usr/bin目录 在环境变量中PATH。所以在终端中直接执行ls命令的名称就可以执行。

举例:

在~家目录下,新建bin文件夹。

cd ~
mkdir bin

获取bin文件夹的路径

[root@ecs-39233 ~]# cd bin/
[root@ecs-39233 bin]# pwd
/root/bin

将/root/bin 配置到环境变量PATH里

vim ~/.bashrc
export PATH=$PATH:/root/bin/

 $PATH,获取PATH的值。

:/root/bin/ ,获取PATH的值后,在后面追加/root/bin/的值。

使环境变量生效:

[root@ecs-39233 bin]# source ~/.bashrc

在/root/bin/ 目录下,新建bash文件。

vim miaojiang.sh
#!/bin/bash
# author: miaojiang
# date: 2023-04-17

echo $PWD
echo $HOME

然后赋予miaojiang.sh 这个文件的全部读写执行权限。

[root@ecs-39233 ~]# sudo chmod +777 /root/bin/miaojiang.sh 

我们在终端里,直接执行 miaojiang.sh 命令,就可以调用 执行miaojiang.sh 这个文件了。

[root@ecs-39233 ~]# miaojiang.sh
/root
/root

报错处理:sh文件出现错误:Permission denied解决办法。

sh文件出现错误:Permission denied解决办法_.sh permission denied_郑嘻嘻~的博客-CSDN博客

下一章:

Shell编程(二)_做测试的喵酱的博客-CSDN博客

猜你喜欢

转载自blog.csdn.net/qq_39208536/article/details/130152751