本文介绍: Shell 是系统用户界面,提供了用户内核进行交互操作的一种接口Shell 将用户输入命令并且把它们送到内核执行然后返回执行结果Shell 是可编程的,它允许用户编写由 Shell 命令组成的程序在 Unix/Linux 里,一个程序/命令做好一件事;复杂问题可以通过多个命令组合解决;形式最简单的 Shell 脚本就是一系列命令构成的可执行文件,并可以被其他脚本复用编写风格良好易读的 Shell 脚本可以提高日常任务自动化程度和准确性。

1 Shell 基础介绍

1.1 Shell 简介

Shell 概述

Shell 发展史

在 Linux 中,有多种 Shell 程序可供选择比如 dashcshzsh 等,默认的 Shell 可以/bin/sh 查看,在etc/passwd修改

查看Shell

查看系统默认安装的 Shell
cat /etc/shells
查看当前登录用户默认 Shell
echo $SHELL
查看当前的 Shell
echo $0

1.2 Shell 脚本(定义、作用、格式权限执行)

Shell 脚本基础知识

在 Unix/Linux 里,一个程序/命令做好一件事;复杂问题可以通过多个命令的组合解决;形式最简单的 Shell 脚本就是一系列命令构成的可执行文件,并可以被其他脚本复用编写风格良好易读的 Shell 脚本可以提高日常任务自动化程度和准确性。

Shell 脚本的约束Shell 脚本可以完成很多任务,但不适用于所有情况

Shell 脚本开发环境

可以在任意文本编辑器中打开文件创建 Shell 脚本。

高级编辑器Vim 和 Emacs,在识别文件后缀为 .sh 后,可以提供语法高亮检查、补全等功能

[root@localhost~]# vim demo.sh     #新建一个本文件,并写入如下内容
#!/bin/bash
echo "Hello World[root@localhost~]# sh demo.sh
Hello World

Shell 脚本指定解释器

Shell 脚本只是静态代码,若要输出结果,还需要解释器的参与。一般在脚本的第一行指定执行此脚本的解释器。如果不指定解释器,脚本也能在默认解释器中正常运行,但出于规范安全考虑建议指定如下:

#!/bin/bash

#!/bin/csh

执行 Shell 脚本

对于脚本文件,我们有两种执行方式

sh script_name.sh
./script_name.sh

Linux 中一切皆文件,脚本/命令/程序都是一个文件,文件作为一个对象具有权限属性。在执行别人发送或从网上下载的脚本时可能会遇到权限问题,赋予执行权限解决

chmod +x script_name.sh

如果某个 Shell 脚本可执行,则可以通过在命令行输入名称调用.被成功调用的前提是,脚本所在路径包含在 $PATH 变量

[root@localhost~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
[root@localhost~]# PATH=$PATH:/New/path
[root@localhost ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/New/path
#永久修改 $PATH 需要在 .bashrc 或 .bash_profile添加 export PATH=“$$PATH:/new/path

后台执行 Shell 脚本

有时候一些脚本执行时间较长,命令行界面会被占用,因此可以采取后台运行脚本:

 ./my_script.sh & 

这种方法退出 Shell 后,脚本进程会随之终止,为了保证脚本一直运行,可以采用:

 nohup ./my_script.sh &

脚本的的标准输出标准错误重定向nohup.out 文件里

使用 jobs 命令可以查看后台运行着的进程

2 Shell 编程基础

2.1 输入输出管道

Linux 中的文本

文本流存在于 Linux 的每一个进程中。Linux 的每个进程启动时,会打开三个文本流的端口标准输入、标准输出标准错误。这三个端口对应着一个程序的输入、输出和异常的抛出。

例如:
bash 中输入一串字符后,bash 进程中的标准输入端口捕获命令行中的输入,进行处理后从标准输出端口中传出,回显屏幕上,如果处理过程中发生异常,则会通过标准错误端口,将异常回显屏幕上。

输出重定向

某些情况下,我们需要保存程序的输出,此时就可以通过重定向,将程序的输出保存到文件中

  1. 将标准输出定向到文件中, 使用这种方式会将程序的标准输出覆盖文件内容
 ls > dir_log
  1. 将标准输出追加到文件中, 使用这种方式会将程序的标准输出追加至文件的末尾
 ls >> dir_log
  1. 执行完命令后,可以通过 cat dir_log 查看保存的文件内容

输入重定向

与输出重定向类似,输入重定向是把程序的标准输入进行重新定向。

输入重定向

内联输入重定向

command << maker &gt;file,同时将输入的内容存成文件

管道

有时需要将一个命令的输出连到另一个命令的输入,如果用重定向实现会较复杂

管道( | )就像现实中的水管一样,可以连接两个命令的输入和输出,甚至是串联多个命令

格式command1 | command2 | command3

[root@localhost ~]# ls /bin/ | grep python | less

管道实际上是进程间通信(IPC)的一种方式

2.2 字符变量运算

2.2.1 Shell 中的字符

和其他编程语言一样,Shell 也有一些保留字(特殊字符),在编写脚本时需要注意。
在这里插入图片描述

2.2.2 Shell 中的变量

任何语言都有变量这个要素。Shell 与其他强类型编程语言如:C,Java 和 C++ 等有很大不同,Shell 中的变量是无类型的。通过一个变量,我们可以引用一块内存区域的值,变量名就是这块内存区域上贴的一个标签

变量赋值variable=value
在这里插入图片描述

变量的类型

在 Linux Shell 中,变量主要有两大类:环境变量用户定义变量。每种类型的变量依据作用域不同,又分为全局变量局部变量

查看变量

对比 printenvset区别:dif -yw <(printenv) <(set)
命令set是Shell中的一个内建命令,它能够显示当前Shell中的变量,已经用户自定义的变量,不管该变量有没有exportset命令允许你更改Shell选项的值并设置位置参数,或者显示Shell变量的名称和值。如果未提供任何选项参数,则会设置显示所有Shell变量和函数名称和值(按照当前语言环境排序),并且输出的格式可以重新用作设置或重置当前设置变量的输入
printenv和env环境变量打印方面是类似的。但是在功能上,env主要用于设置环境变量并运行指定的命令命令,而printenv是为了打印环境变量
set则是一个Shell的内建命令,与Shell有关,用于设置Shell的属性

修改变量

使用变量

Shell 变量命名规则

定义变量的格式

variable=value
variable='value'
variable="value"
扩展变量

在以下示例中,如果不使用花括号,Bash 会将$FIRST_$LAST 解释为变量 $FIRST_ 后跟变量 $LAST,而不是由_ 字符分隔的变量 $FIRST 和 $LAST。
在这里插入图片描述

因此,在此情况下,必须使用花括号引用的形式才能使变量扩展正确运行。

变量的赋值和输出

2.2.3 Shell 的算术扩展

算术扩展可用于执行简单整数算术运算
语法:$[表达式]
如:

[root@localhost ~]# echo $[1+9]
10
[root@localhost ~]# echo $[8*8]
64
[root@localhost ~]# count=1;echo $[$[$count+3]*2]
8
在 Shell 中计算时间

定义24小时,60分钟,60秒变量,定义每天秒数变量并赋值,输出变量

[root@localhost ~]# SEC_PER_MIN=60
[root@localhost ~]# MIN_PER_HR=60
[root@localhost ~]# HR_PER_DAY=24
[root@localhost ~]# SEC_PER_DAY=$[$SEC_PER_MIN*$MIN_PER_HR*$HR_PER_DAY]
[root@localhost ~]# echo "There are $SEC_PER_DAY seconds in a day"
There are 86400 seconds in a day
算术运算常用表达式

在这里插入图片描述

算术运算优先级

优先级由高到低如下:
在这里插入图片描述

变量递增的前置后置区别

i++ 要开辟一个变量来保存 i 的值 并返回,然后让 i 这个变量 的值 +1 。而 ++i 直接把 1 加到 i 这个 变量的空间中去,并返回这个空间 中的值, 没有开辟任何临时空间性能更高。

2.3 语句(条件循环)

Shell 中的结构化命令

在 Shell 脚本里除了顺序执行,还需要一些额外的逻辑控制流程

和其他编程语言类似, Shell 中的结构化命令主要包括条件循环两类

条件语句

Shell 中的 if 和其他 if 判断条件不太一样,需注意。

If-then 语句
语法:

if command
    then
       commands
 fi

Bash Shell 会先执行 if 后面的语句,如果其退出状态为 0,则会继续执行 then 部分的命令,否则会执行脚本中的下一个命令。

分支判断语句

在涉及条件判断时,可能会使用较为繁琐的 if-then-else 语句,通过 elif 语句频繁检测同一个变量的值,此时更适合使用 case 语句
语法:

case variable in
    pattern1 | pattern2) commands1;;
    pattern3) commands2;;
    *) default commands;;
esac

循环语句

Shell 脚本中常会遇到一些重复任务,相当于循环执行一组命令直到满足了某个特定条件

常见的循环语句有三种:for、while、until

循环控制符有两种:breakcontinue 用于控制循环流程的转向

for 循环
#Shell风格语法
for var in list
    do
        commands
    done

#例:
for i in {1..10}
do
        printf "$in"
done

#c语言风格
for ((var assignment ; condition ; iteration process))
do
        commands
done

#例:
for (( i = 1; i < 10 ; i++))
do
    echo “Hellodone

do和done之间的命令称为循环体,执行次数和list表中常数或字符串的个数相同。for循环,首先将in后list列表的第一个常数或字符串赋值给循环变量,然后执行循环体,以此执行list最后执行done命令后的命令序列

for 循环中的列表
[root@localhost~]# for HOST in host1 host2 host3; do echo $HOST; done 
host1
host2
host3
[root@localhost ~]# for HOST in host{1..3}; do echo $HOST; done             
host1
host2
host3
[root@localhost~]# for EVEN in $(seq 2 2 8); do echo "$EVEN"; done;
2
4
6
8
for 循环奇数累加器

定义奇数累加器文件,并执行
参考脚本:

#!/bin/bash

sum=0
for i in {1..100..2}
do
    let "sum+=i"
done    
echo "sum=$sum"
for 循环文件展示

展示目录下所有文件
参考脚本:

#!/bin/bash

for file in $(ls)
do
   echo "file: $filedone
while 循环

也称为前测试循环语句,重复次数是利用一个条件控制是否继续重复执行这个语句。为避免死循环,必须保证循环体中包含循环出口条件

#!/bin/bash

sum=0;i=1 
while(( i <= 100 ))
do
     let "sum+=i"
     let "i += 2"   
done
      echo "sum=$sum"
until 循环

与 while 循环类似,但是跳出循环的条件判断有所区别

#!/bin/bash
#奇数累加器

sum=0;i=1 
until(( i > 100 ))
do
     let "sum+=i"
     let "i += 2"   
done
     echo "sum=$sum"
使用循环打印乘法表

参考脚本:

#!/bin/bash

for (( i = 1; i <=9; i++ ))do        
    for (( j=1; j <= i; j++ ))do       
    let "temp = i * j"             
    echo -n "$i*$j=$temp  "     
    done          
printfn”
done

3 Shell 编程最佳实践

3.1 调试

Shell 脚本错误故障排除

编写、使用或维护 Shell 脚本的管理员不可避免地会遇到脚本的错误

调试模式

脚本上激活调试模式,请向脚本第一行中的命令解释器添加 -x 选项
如此前乘法表,进行如下修改:

#!/bin/bash -x

bash 的调试模式打印出脚本执行前由脚本执行的命令,已执行的所有 shell 扩展的结果都将显示打印输出中,所有变量数据状态会实时打印,以供跟踪

bash -x adder.sh

评估退出代码

  • 每个命令返回一个退出状态,也通常称为返回状态或退出代码
  • 退出代码可以用于脚本的调试
  • 以下示例说明了几个常见命令的执行和退出状态检索
[root@localhost tmp]# ls /etc/hosts
/etc/hosts
[root@localhost tmp]# echo $?
0
----------------------------------------------------------------
[root@localhosttmp]# ls /etc/nofile
ls: cannot access /etc/nofile: No such file or directory
[root@localhost tmp]# echo $?
2
  • 在脚本中使用退出代码
  • 一旦执行,脚本将在其处理所有内容之后退出,但是有时候可能需要中途退出脚本,比如在遇到错误条件时
  • 可以通过在脚本中使用 exit 命令来实现这一目的,当脚本遇到 exit 命令时,脚本将立即退出并跳过对脚本其余内容的处理
[root@localhosttmp]# cat hello.sh 
#!/bin/bash
echo "Hello World"
exit 1
[root@localhosttmp]# ./hello.sh 
Hello World
[root@localhost tmp]# echo $?
1

3.2 语法风格

以下是要遵循的一些具体做法:

修改后的脚本:

#!/bin/bash
# 此脚本是读取关于kernel相关的软件包信息,并从RPM数据库查询软件包安装时间
PACKAGETYPE=kernel
PACKAGES=$(rpm -qa | grep $PACKAGETYPE)
# 循环处理信息
for PACKAGE in $PACKAGES; do 
        #查询每个软件包安装时间
        INSTALLEPOCH=$(rpm -q --qf "%{INSTALLTIME}n" $PACKAGE)
        # 把时间转换为普通的日期时间
        INSTALLDATETIME=$(date -d @$INSTALLEPOCH)
        # 打印信息
        echo "$PACKAGE was installed on $INSTALLDATETIME"
done

3.3 最佳实践示例

检测日志告警信息邮件通知

场景描述
某运营商要求对当前环境日志文件“error.log”进行长期监测,如发现关键词“danger”,则发送告警邮件

要求:

  1. 运行监测脚本
  2. 日志初始内容为空,写入关键词“danger”
  3. 自动发送邮件(写入 mail 替代)
#!/bin/bash
# 日志检测脚本 test.sh

tail -f /var/log/error.log | while read danger;
do echo ‘mail’ >> /var/log/error.log;
sleep 1m;
done

#!/bin/bash
# 模拟报错脚本 addlog.sh

echo ‘danger’ >> /var/log/error.log
./test.sh &amp;
./addlog.sh
cat /var/log/error.log

原文地址:https://blog.csdn.net/qq_51601649/article/details/126001311

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_13773.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注