Shell快速入门笔记

文章目录

  • Shell 快速入门笔记
    • 1、Shell概述
    • 2、Shell初体验
    • 4、注释
    • 5、变量
    • 6、数据类型
      • 6.1 字符串
      • 6.2 数组
    • 7、参数传递
    • 8、运算符
    • 9、常用命令
      • 9.1 echo命令
      • 9.2 printf命令
      • 9.3 test命令
    • 10、流程控制
      • 10.1 条件判断
      • 10.2 循环
    • 11、函数
    • 12、输入/输出重定向
      • 12.0 前置知识
      • 12.1 输出重定向
      • 12.2 输入重定向
    • 13、文件包含

Shell 快速入门笔记

1、Shell概述

  • Shell是什么

    在Linux中,Shell是一种命令行界面(CLI),用于与操作系统交互和运行各种命令和程序。Linux操作系统支持多种不同的Shell,每种Shell都有自己的特点和功能。

    个人理解:在Linux中,Shell是一种C语言编写的程序,类似于其它编程语言,它是解释执行的,是连接用户和操作系统的桥梁

  • Shell在计算机中所处的位置

  • Shell能干什么

    Shell是一种脚本语言,所以一般讨论Shell的作用,都是说Shell编写的程序,即Shell脚本的作用

    • 自动化任务:Shell脚本可以用于执行一系列操作和命令,从而自动化一些任务。例如,你可以编写一个Shell脚本来备份你的文件系统,定时运行这个脚本,以确保你的数据得到保护。
    • 批量处理数据:Shell脚本可以用于处理大量的数据。例如,你可以编写一个Shell脚本来查找一个文件夹中所有的文本文件,并将它们转换为另一种格式。
    • 系统管理:Shell脚本可以用于管理系统的各个方面,例如安装软件包、创建用户和设置权限等。
    • 任务调度:Shell脚本可以用于创建和管理计划任务,例如定期执行系统备份或日志清理等。
    • 监控和管理进程:Shell脚本可以用于监控和管理进程,例如启动、停止或重启进程,或者检查进程是否在运行等。
  • Linux中Shell有哪些

    • Bourne Shell(/bin/sh):最早的Unix shell,由Stephen Bourne开发,也称为sh。它是现代Unix shell的基础,可以在几乎所有的Unix和Linux系统上找到。
    • C Shell(/bin/csh):由Bill Joy开发,也称为csh。它是一种基于C语言的shell,具有交互式命令行编辑和命令历史记录等特性。在许多Linux系统中,可以通过安装csh软件包来使用它。
    • Korn Shell(/bin/ksh):由David Korn开发,也称为ksh。它是Bourne Shell的扩展,提供了更多的功能和命令,如命令行编辑、作业控制、数组等。它在Solaris和AIX等Unix系统中广泛使用。
    • Bourne-Again Shell(/bin/bash):由Brian Fox和Chet Ramey开发,也称为bash。它是Bourne Shell的扩展,添加了许多新特性,如命令行编辑、自动补全、历史命令等。它是Linux系统默认的shell。
    • Z Shell(/bin/zsh):由Paul Falstad开发,也称为zsh。它是一种功能强大的shell,具有高级的命令行编辑和自动补全、路径展开等特性。它通常在Mac OS X和一些Linux系统中使用。

    除了上述这些主要的shell,还有其他一些不太常用的shell,如fish(Friendly Interactive Shell)、rc shell、es shell等

  • Shell脚本是什么

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

    备注:业界所说的 shell 通常都是指 shell 脚本,但读者朋友要知道,shell 和 shell script 是两个不同的概念。

2、Shell初体验

按照惯例😄,我们在学习一门新的语言时,都先学会如何打印"Hello World!",现在就让我们来学习如何使用Shell打印一个”Hello World!“吧(●’◡’●)

  • Shell脚本运行所需要的东西shell编辑器+shell解释器

    shell编辑器一般用的是vi\vim,shell解释器一般用的是bash解释器

  • 运行一个Shell脚本的主要步骤

    • Step1编写Shell

      1)创建一个新的文本文件,通常使用.sh作为文件扩展名

      # 在当前目录创建一个名为 hello.sh的文件
      vim hello.sh
      

      2)编码

      #!/bin/bash
      echo "Hello World !"
      

      第一行:指定一个Shell解释器,这里使用的是bash解释器

      第二行:使用Shell提供的指令,编写一个Shell程序

      3)保存退出:按下ESC,从输入模式进入命令模式,然后按下:进入编辑模式,然后输入wq回车

    • Step2运行Shell,运行Shell脚本的方式有很多种,这里演示一些常见的方式

      前面我们shell脚本的路径是:/home/ghp/hello.sh

      • 方式一绝对路径/相对路径

        绝对路径:

        chmod +x hello.sh
        ./home/ghp/hello.sh
        

        相对路径:

        chmod +x hello.sh
        ./hello.sh
        

        备注:新建的文件默认是没有执行(x)权限的,需要赋值

      • 方式二sh/bash

        # sh方式
        sh hello.sh
        # bash方式
        bash hello.sh
        

        这种方式的特点:使用这种方式不需要给文件设置执行权限,但是会导致shell脚本可能不是由我们指定的shell解释器执行,

        比如,我们使用 #!指定的是 bash 解释器,但是我们使用 sh hello.sh运行,此时执行该脚本的shell解释器就不是我们指定的 bash 解释器,而变成了 sh 解释器。所以使用这种方式,在编写Shell脚本时可以直接不指定 shell 解释器

        sh和bash的区别和联系/bin/sh是早期版本,是一种便携方式的解释性脚本语言,自带有posix便携式功能,以该方式声明的脚本,脚本中间发生错误会终止脚本的运行,不再运行下面的代码/bin/bash,是/bin/sh的升级版,默认没有开启posix便携模式,所以以 /bin/bash 声明的脚本,中间即使发生错误,依然会继续向下运行

        可以简单的理解:/bin/sh 等价于 /bin/bash --posix

        注意:现在Linux(2.6.18)中,sh已经被bash整合了,我们使用的 sh 其实是 bash 的软链接,sh 就是 bash --posix,可以使用man shman bash 测试当前系统 sh 是否已经被bash整合了

      • 方式三./source

        # . 方式
        . hello.sh
        # source 方式
        source hello.sh
        

        备注:需要给文件赋予执行(x)权限。./source 都是继承 /bin/bash 的权限,和 bash 方式不同的是,它不会开启一个子shell线程,而是直接在当前shell进程下执行的,因为他们是内建命令,所以脚本中赋值的本地变量也会影响当前shell的,用的时候一定要注意(尽量使用前面的3种方式),一般方式三都是用于执行配置文件

      总结

      1. 方式一需要Shell脚本有可执行权限,方式二和方式三不需要
      2. 方式一和方式二在脚本执行时,会开启一个子shell环境,在子shell执行完成后,子shell环境随即关闭,然后又回到当前shell中;而方式三不会开启子shell,而是直接在当前shell线程中进行执行脚本

4、注释

  • 注释的定义:注释是在Shell脚本中用来标识代码的解释或说明的一种特殊文本。在执行Shell脚本时,注释会被忽略,不会对程序的执行造成任何影响。

    注意:shell脚本的第一行的#!注释是有作用的,它指定了使用哪一个shell解释器去执行这个脚本(但如何使用bash/sh去执行脚本就不一定就是这个解释器去执行)

  • 注释的作用

    • 提高代码的可读性和可维护性。通过注释,程序员可以更加清晰地了解代码的意图和实现方法,从而更方便地进行代码的修改和调试。
    • 方便代码的协作和共享。注释可以帮助其他程序员更好地理解和使用自己的代码,减少因为代码不明确而导致的沟通障碍和误解。
  • 注释的分类

    • 行注释(Line Comments):行注释是在一行代码的末尾加上一段注释,通常使用“#”符号来表示。行注释只对当前行有效,不会影响后续代码的执行。
    • 块注释(Block Comments):块注释是在多行代码中间加上一段注释,通常使用“:<<”和“:”符号来表示。块注释可以跨越多行,但必须以“:”符号结束。
    • 文档注释(Document Comments):文档注释是用来描述代码整体的一种注释,通常放置在代码的开头。文档注释可以使用特定的标记和格式,如“/**”和“*/”符号,以方便生成文档或注释。

    示例:

    行注释:
    # 注释内容
    
    块注释(下面的EOF可以替换称其它字符,比如END、!、?...)
    :<<EOF
    注释内容
    注释内容
    注释内容
    EOF
    
    文档注释:
    #!/bin/bash
    #
    # Script name: backup.sh
    #
    # Description:
    # This script is used to backup files from a source directory to a destination directory.
    #
    # Usage:
    # ./backup.sh <source directory> <destination directory>
    #
    # Options:
    # -v : verbose output
    #
    # Return values:
    # 0 : success
    # 1 : error
    #
    # Examples:
    # ./backup.sh /home/user /mnt/backup
    # ./backup.sh -v /home/user /mnt/backup
    #
    
    # Script code goes here...
    
  • 注释应当遵循以下规范

    • 注释应该简洁明了,不要过度注释,也不要遗漏重要的注释信息。注释应该突出代码中最重要、最难理解、最易出错的部分,对这些部分进行详细的解释和说明。
    • 注释应该使用简单、易懂的语言,避免使用专业术语和难懂的缩写。注释应该能够被任何人理解,包括不具备编程背景的人。
    • 注释应该与代码保持一致,注释应该与代码在格式、缩进、注释位置等方面保持一致。注释应该尽量放在代码的上方或右侧,而不是在代码中间或下方。
    • 注释应该避免错误和歧义,注释应该准确地反映代码的意图和行为,避免产生歧义和误解。注释应该在代码更新或修改后及时更新,以保证注释与代码的一致性。
    • 注释应该按照一定的规范和格式进行编写,例如使用特定的注释符号、排版方式、注释级别等。在项目中,应该制定一份注释规范和标准,对注释的格式、内容、使用方法等进行明确规定,以保证注释的一致性和可读性。

5、变量

  • 变量的命名规则

    • 命名只能使用英文字母,数字和下划线_,首个字符不能以数字开头

    • 不能使用标点符号或空格

    • 不能使用 Shell 中的关键字

    • 变量名和等号之间不能有空格

    以上这四点是硬性要求,不按上诉规会直接报错,而对于常量或者环境变量的命名一般我们都需要使用全大写字母,每个单词之间使用_分隔(PS:这只是规范,不是规则)

  • Shell中常见的变量

    • 环境变量(Environment Variables):环境变量是Shell进程中的全局变量,可以由Shell启动时设置,也可以在运行时使用export命令设置。常见的环境变量包括PATH、HOME、USER等。
    • 用户定义变量(User-Defined Variables):用户定义变量是Shell脚本中自己定义的变量,可以存储任何类型的数据。变量名通常由字母、数字和下划线组成,但不能以数字开头。
    • 位置参数变量(Positional Parameters):位置参数变量是指Shell脚本中传递给脚本的参数。$0表示脚本本身,$1$2$3…分别表示第一个、第二个、第三个参数,以此类推。
    • 特殊变量(Special Variables):特殊变量是Shell中预定义的一些特殊变量,具有特殊的含义。例如,$?表示上一个命令的返回值,$$表示当前Shell进程的进程号。
    • 只读变量(Read-Only Variables):只读变量是指Shell中不能修改其值的变量,通常用来保存Shell脚本的一些固定值。例如,$RANDOM表示一个随机数,$BASH_VERSION表示当前Shell的版本号等。我们可以通过readonly 关键字来定义只读变量
    • 数组变量(Array Variables):数组变量是一种特殊的变量,可以在一个变量中存储多个值。在Shell中,可以使用下标来访问和修改其中的元素

    主要分为三大类

    • 自定义变量(局部变量):一般是指开发者在Shell脚本中定义的变量,这些变量仅在当前Shell示例中有效,其它Shell示例无法访问,属于局部变量
    • Linux中已定义的环境变量(环境变量):所有的程序,包括Shell启动的程序,都能访问环境变量(比如PATH、HOME……),有些程序需要环境变量来保证其正常运行(必要的时Shell脚本也可以定义环境变量)
    • Shell中的预定义变量(Shell变量):Shell变量是由shell程序设置的特殊变量。Shell变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了shell的正常运行
  • 常用操作

    • 查看环境变量

      • set:显示当前shell中自定义的变量,包括用户的环境变量,按变量名称排序。仅在当前Shell有效,可以显示Shell的自定义的变量

        备注:直接 set 是查看当前系统中的所有环境变量,这个输出比较多,一般我们可以搭配管道符+grep命令进行筛选

        Linux的declare命令不加参数和set的作用类似

      image-20230329105147768

      • env:查看所有环境变量,也可以设置环境变量。仅在当前会话中有效,可以显示和设置用户环境变量(Linux中定义的环境变量),用法和set类似
      • export:显示当前导出成用户变量的shell变量(当一个变量被导出时,它将成为子进程的环境变量,这意味着子进程可以访问该变量),并显示变量的属性(是否只读),按变量名称排序,用法和set类似

      set和env都是用来查询环境变量,而export是用来查询导出称用户变量的Shell变量;set作用范围要大于env,set能够查询到env不能查询到的Shell中自定义的变量。以上就是三者之间的主要区别

    • 删除变量unset

      username=ghp # 自定义一个username变量
      set | grep "username" # 查看username变量
      unset username # 删除username变量
      

      注意:只能删除只读变量

    • 只读变量readonly

      myUrl="https://www.runoob.com"
      unset myUrl
      echo $myUrl
      

6、数据类型

  • Shell中的数据类型

    • 字符串(String):字符串是Shell脚本中最常用的数据类型之一。字符串可以使用单引号(')或双引号(")来定义,可以包含任何字符。
    • 数字(Number):Shell脚本中也支持数字类型,包括整数和浮点数。通常使用let命令或者$((expression))语法来计算数字。
    • 数组(Array):数组是一种特殊的数据类型,可以在一个变量中存储多个值。在Shell中,数组可以使用下标来访问和修改其中的元素。
    • 布尔型(Boolean):Shell脚本中没有原生的布尔类型,通常使用0表示假(false),1表示真(true)。
    • 空值(Null):空值表示一个变量没有任何值。在Shell中,可以使用unset命令来清除一个变量的值。

    除了以上常见的数据类型,还有一些特殊的数据类型,如文件描述符命令输出等。掌握这些数据类型可以帮助Shell脚本编程更加灵活和高效。

6.1 字符串

  • 字符串:字符串可以分为三类,单引号字符串双引号字符串不加引号的字符串

    • 单引号字符串

      # hello.sh
      str='this is a string'
      echo $str # this is a string
      

      注意事项

      1. 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;

      2. 单引号字串中不能出现单独一个的单引号(对单引号使用转义符后也不行),但可成对出现,作为字符串拼接使用。

    • 双引号字符串

      # hello.sh
      your_name="ghp"
      str="my name is \"$your_name\"! \n"
      echo $str # my name is ghp!
      

      如果出现了command not fount,这是由于 hello.sh 编码格式不对,我就踩坑了,=左右一定不能有空格,因为在写Java代码时,写空格写习惯了

      双引号相较于单引号的优点

      1. 可以使用转义符,单引号是直接输出
      2. 可以直接在字符串中使用变量,单引号只能通过拼接
    • 不加引号的字符串

      str=abc
      echo $str # abc
      

      注意:定义的变量不能含有空格

  • 常见的字符串操作

    • 字符串拼接

      your_name="ghp"
      # 使用双引号拼接
      str1="hello, "$your_name" !"
      str2="hello, ${your_name} !"
      echo $str1 # hello, ghp ! 
      echo $str2 # hello, ghp !
      # 使用单引号拼接
      str3='hello, '$your_name' !'
      str4='hello, ${your_name} !'
      echo $str3  # hello, ghp !
      echo $str4  # hello, ${your_name} !
      
    • 获取字符串长度

      string="abcd"
      echo ${#string} # 4
      echo ${#string[0]} # 4
      
    • 获取子字符串

      str="runoob is a great site"
      echo ${str:6:8} # is a gr
      

      备注:从第7个字符开始,第7个字符是b后面的空格,然后往后数8个字符,也就是到 gr 结束runoob[ is a gr]eat site。类似于Python中的切片

    • 查找字符

      str="runoob is a great site"
      echo `expr index "$str" io` # 4
      

      备注:查找字符io,谁先出现就先计算谁,这里o先出现,它是第4个字符,所以输出4

6.2 数组

  • 数组的定义

    数组名=(值1 值2 ... 值n)
    # 示例:
    arr=(1 2 3)
    # 备注:空格的数量没有影响,字符串数组要用引号
    arr=(
    1
    2
    3
    )
    arr[0]=1
    arr[1]=2
    arr[3]=3
    
  • 常见的数组操作

    • 获取数组中的元素

      # 读取数组中的元素
      ${数组名[下标]}
      # 示例
      arr=(1 2 3)
      echo ${arr[1]} # 2
      echo ${arr[@]} # 1 2 3
      
    • 获取数组的长度

      # 取得数组元素的个数
      ${#arr[@]}
      # 或者
      ${#arr[*]}
      # 取得数组单个元素的长度
      ${#arr[下标]}
      

7、参数传递

  • $n:n表示一个正整数,1表示第一个参数,2表示第二个参数……
  • $#:传递到脚本的参数个数
  • $*:显示所有向脚本传递的参数
  • $@:显示所有向脚本传递的参数
  • $$:脚本运行的当前进程ID号
  • $!:后台运行的最后一个进程ID号
  • $-:显示Shell使用的当前选项,与set命令功能相同
  • $?:显示最后命令的退出状态,0没有错误,其它任何值都表明有错误
  • $_ :表示的是打印上一个输入参数行, 当这个命令在开头时, 打印输出文档的绝对路径名

示例

#!/bin/bash
echo "Shell 传递参数实例!";
echo "\$0 执行的文件名:$0";
echo "\$1 第一个参数为:$1";
echo "\$2 第二个参数为:$2";
echo "\$3 第三个参数为:$3";
echo "\$# 传递脚本的参数个数: $#"
echo "\$* 所有传入脚本的参数: $*"
echo "\$@ 所有传入脚本的参数: $@"
echo "\$$ 脚本运行的当前进程ID: $$"
echo "\$! 后台运行的最后一个进程ID: $!"
echo "\$- shell使用的当前选项: $-"
echo "\$? 最后命令退出的状态: $?"
echo "\$_ 上一个输入参数行: $_"
sh test.sh 1 2 "3"
Shell 传递参数实例!
$0 执行的文件名:test.sh
$1 第一个参数为:1
$2 第二个参数为:2
$3 第三个参数为:3
$# 传递脚本的参数个数: 3
$* 所有传入脚本的参数: 1 2 3
$@ 所有传入脚本的参数: 1 2 3
$$ 脚本运行的当前进程ID: 53206
$! 后台运行的最后一个进程ID: 
$- shell使用的当前选项: hB
$? 最后命令退出的状态: 0
$_ 上一个输入参数行: $? 最后命令退出的状态: 0
  • $* $@ 区别

    • 相同点:都是引用所有参数。
    • 不同点:只有在双引号中体现出来。假设在脚本运行时写了三个参数 1、2、3,,则 "* " 等价于 “1 2 3”(传递了一个参数),而 “@” 等价于 “1” “2” “3”(传递了三个参数)。
    #!/bin/bash
    echo "-- \$* 演示 ---"
    for i in "$*"; do
        echo $i
    done
    
    echo "-- \$@ 演示 ---"
    for i in "$@"; do
        echo $i
    done
    
    sh test.sh 1 2 3
    -- $* 演示 ---
    1 2 3
    -- $@ 演示 ---
    1
    2
    3
    

8、运算符

Shell 编程支持下面几种运算符

  • 算数运算符
  • 关系运算符
  • 布尔运算符
  • 逻辑运算符
  • 字符串运算符
  • 文件测试运算符

详情请参考:Shell 基本运算符 | 菜鸟教程 (runoob.com)

  • 计算指令/符号

    image-20230404152818387

  • 算术运算符

    假定变量 a 为 10,变量 b 为 20

    image-20230404094358757

    注意

    1. 条件表达式要放在方括号之间,并且要有空格,例如: [a==b] 是错误的,必须写成 [ a == b ],但是在[]中进行数值计算时,不需要空格,比如[a+b]
    2. *前边必须加反斜杠\才能实现乘法运算
    3. 在 MAC 中 shell 的 expr 语法是:$((表达式)),此处表达式中的 *"不需要转义符号 \
  • 关系运算符

    假定变量 a 为 10,变量 b 为 20

    image-20230404095031496

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

  • 布尔运算符

    假定变量 a 为 10,变量 b 为 20

    image-20230404095301467

  • 逻辑运算符

    假定变量 a 为 10,变量 b 为 20

    image-20230404095334217

  • 字符串运算符

    下表列出了常用的字符串运算符,假定变量 a 为 “abc”,变量 b 为 “efg”:

    image-20230404095409691

  • 文件测试运算符

    image-20230404095600834

    其他检查符:

    • -S: 判断某文件是否 socket。
    • -L: 检测文件是否存在并且是一个符号链接。

9、常用命令

9.1 echo命令

Shell 的 echo 指令与 PHP 的 echo 指令类似,都是用于字符串的输出。命令格式:

echo [参数] string

参数说明

  1. -n:当指定-n选项时,其后的换行符被抑制;即不会在最后自动换行
  2. -e:当指定-e选项时,则将解释以下反斜杠转义字符

您可以使用echo实现更复杂的输出格式控制。

  • 显示普通字符串:

    echo "It is a test"
    

    这里的双引号完全可以省略,以下命令与上面实例效果一致:

    echo It is a test
    
  • 显示转义字符

    echo "\"It is a test\""
    

    结果将是:

    "It is a test"
    

    同样,双引号也可以省略

  • 显示变量

    read 命令从标准输入中读取一行,并把输入行的每个字段的值指定给 shell 变量

    #!/bin/sh
    read name 
    echo "$name It is a test"
    

    以上代码保存为 test.sh,name 接收标准输入的变量,结果将是:

    [root@www ~]# sh test.sh
    OK                     #标准输入
    OK It is a test        #输出
    
  • 显示换行

    echo -e "OK! \n" # -e 开启转义
    echo "It is a test"
    

    输出结果:

    OK!
    
    It is a test
    
  • 显示不换行

    #!/bin/sh
    echo -e "OK! \c" # -e 开启转义 \c 不换行
    echo "It is a test"
    

    输出结果:

    OK! It is a test
    
  • 显示结果定向至文件

    echo "It is a test" > myfile
    
  • 原样输出字符串,不进行转义或取变量(用单引号)

    echo '$name\"'
    

    输出结果:

    $name\"
    
  • 命令执行结果

    echo `date`
    

    结果将显示当前日期

    Thu Jul 24 10:08:46 CST 2014
    

9.2 printf命令

上一章节我们学习了 Shell 的 echo 命令,本章节我们来学习 Shell 的另一个输出命令 printf。

printf 命令模仿 C 程序库(library)里的 printf() 程序。

printf 由 POSIX 标准所定义,因此使用 printf 的脚本比使用 echo 移植性好。

printf 使用引用文本或空格分隔的参数,外面可以在 printf 中使用格式化字符串,还可以制定字符串的宽度、左右对齐方式等。默认的 printf 不会像 echo 自动添加换行符,我们可以手动添加 \n

printf语法格式:

printf  format-string  [arguments...]

参数说明

  1. format-string: 为格式控制字符串

  2. arguments: 为参数列表

示例

#!/bin/bash
printf "Hello, Shell\n"
printf "%-10s %-8s %-4s\n" 姓名 性别 体重kg  
printf "%-10s %-8s %-4.2f\n" 郭靖 男 66.1234
Hello, Shell
姓名     性别   体重kg
郭靖     男      66.12

备注%s %c %d %f 都是格式替代符,%s 输出一个字符串,%d 整型输出,%c 输出一个字符,%f 输出实数,以小数形式输出。

%-10s 指一个宽度为 10 个字符(- 表示左对齐,没有则表示右对齐),任何字符都会被显示在 10 个字符宽的字符内,如果不足则自动以空格填充,超过也会将内容全部显示出来。%-4.2f 指格式化为小数,其中 .2 指保留2位小数。

知识拓展:常见的转义符

image-20230404144254425

9.3 test命令

test命令主要用于:数值测试、字符串测试、文件测试

  • 数值测试

    image-20230404144553476

    示例:

    #!/bin/bash
    num1=100
    num2=100
    if test $[num1] -eq $[num2]
    then
        echo '两个数相等!'
    else
        echo '两个数不相等!'
    fi
    
    两个数相等!
    
  • 字符串测试

    image-20230404144543394

    示例:

    #!/bin/bash
    num1="a b"
    num2="ab"
    if test $num1 = $num2
    then
        echo '两个字符串相等!'
    else
        echo '两个字符串不相等!'
    fi
    
    两个字符串不相等!
    
  • 文件测试

    image-20230404144606668

    示例:

    #!/bin/bash
    if test -e /home/ghp/test.sh
    then
        echo '文件已存在!'
    else
        echo '文件不存在!'
    fi
    
    文件已存在!
    

知识拓展:逻辑操作符

Shell 还提供了与 -a(与) 、-o (或)、!(非) 三个逻辑操作符用于将测试条件连接起来,其优先级为: ! 最高, -a 次之, -o 最低

#!/bin/bash
if test ! -e /home/ghp/test.sh -o -e /home/ghp/unexite.sh
then
    echo '至少有一个文件存在!'
else
    echo '两个文件都不存在'
fi
两个文件都不存在

备注:-e /home/ghp/test.sh得到的结果为 真,但是前面有一个 ! 从而导致结果为 假,-o表示或,只有有一个为真就为真,结果-e /home/ghp/unexite.sh 的结果也是 假,两个都为假,最终的结果就为假了

10、流程控制

10.1 条件判断

  • if

    if condition
    then
        command1 
        command2
        ...
        commandN 
    fi
    
  • if else

    if condition
    then
        command1 
        command2
        ...
        commandN
    else
        command
    fi
    

    注意:else中的command不能为空,在Java中是可以的,但是Shell中是不允许的

  • if else if esle

    if condition1
    then
        command1
    elif condition2 
    then 
        command2
    else
        commandN
    fi
    

示例

if 0
then
    echo "条件为真"
else
   # echo "条件为假"
fi

else为空直接报错:

image-20230404152005707

取消注释,就能运算成功了:

image-20230404152152875

10.2 循环

11、函数

Shell中的函数总共非为两大类:有返回值的函数和没有返回值的函数

函数的定义方式:

[ function ] funname [()]

{

    action;

    [return int;]

}

备注:这里的[]表示Shell中的运算符,而是表示这个参数可以省略

示例

#!/bin/bash
# 没有返回值的函数
demoFun(){
    echo "这是我的第一个 shell 函数!"
}
echo "-----demoFun函数开始执行-----"
demoFun
echo "-----demoFun函数执行完毕-----"

# 有返回值的函数
funWithReturn(){
    echo "这个函数会对输入的两个数字进行相加运算..."
    echo "输入第一个数字: "
    read aNum
    echo "输入第二个数字: "
    read anotherNum
    echo "$aNum$anotherNum 相加的结果为:"
    return $(($aNum+$anotherNum))
}
funWithReturn
echo "输入的两个数字之和为 $? !"

image-20230404153736384

#!/bin/bash
# 带参函数
funWithParam(){
    echo "第一个参数为 $1 !"
    echo "第二个参数为 $2 !"
    echo "参数总数有 $# 个!"
    echo "作为一个字符串输出所有参数 $* !"
}
funWithParam 1 2 3

image-20230404154801954

注意:获取第10个参数是,不能这样写$10,要这样写${10}

12、输入/输出重定向

Linux Shell 重定向分为两种,一种输入重定向,一种是输出重定向;从字面上理解,输入输出重定向就是「改变输入与输出的方向」的意思。

12.0 前置知识

  • 什么是输入重定向和输出重定向

    输入方向就是数据从哪里流向程序。数据默认从键盘流向程序,如果改变了它的方向,数据就从其它地方流入,这就是输入重定向。输出方向就是数据从程序流向哪里。数据默认从程序流向显示器,如果改变了它的方向,数据就流向其它地方,这就是输出重定向

  • 什么是标准输入设备和标准输出设备

    计算机的硬件设备有很多,常见的输入设备有键盘、鼠标、麦克风、手写板等,输出设备有显示器、投影仪、打印机等。不过,在 Linux 中,标准输入设备指的是键盘标准输出设备指的是显示器

  • 什么是文件描述符

    Linux 中一切皆文件,包括标准输入设备(键盘)和标准输出设备(显示器)在内的所有计算机硬件都是文件。

    为了表示和区分已经打开的文件,Linux 会给每个文件分配一个 ID,这个 ID 就是一个整数,被称为文件描述符(File Descriptor)。

    image-20230404160509743

12.1 输出重定向

Bash 支持的输出重定向符号:

image-20230404162416263

备注:在输出重定向中,>代表的是覆盖,>>代表的是追加

注意

  1. 输出重定向的完整写法其实是fd>file或者fd>>file,其中 fd 表示文件描述符,如果不写,默认为 1,也就是标准输出文件。当文件描述符为 1 时,一般都省略不写,如上表所示;当然,如果你愿意,也可以将command >file写作command 1>file,但这样做是多此一举。当文件描述符为大于 1 的值时,比如 2,就必须写上。

  2. fd>之间不能有空格,否则 Shell 会解析失败;>file之间的空格可有可无。为了保持一致,我习惯在>两边都不加空格。

    错误示例:

    echo "你好" 1 >log.txt
    

    在log.txt中你会发现是

    "你好" 1
    

    这是因为上面1和>之间存在空格,它的语句变成了 echo “你好” 1 1>log.txt

示例

# 将 Hello World! 输出到 test 文件(test文件不需要先创建,Shll会自动在当前目录创建test文件)
echo "Hello World\!" > test
# 查看test文件中的内容
cat test
Hello World\!
for str in "abcd 123 张三 !@"
do
    echo $str >> test  # 将输入结果以追加的方式重定向到文件
done

image-20230404164324087

12.2 输入重定向

Bash支持的输入重定向:

image-20230404164603923

PS:和输出重定向类似,输入重定向的完整写法是fd<file,其中 fd 表示文件描述符,如果不写,默认为 0,也就是标准输入文件。

示例

准备工作

需要熟悉wc命令(不知道为什么看到这个命令我脑子里蹦出来一句wc)

wc  [参数]  [文件名]

参数说明:-c选项统计字节数;-w选项统计单词数;-l选项统计行数

之前用过的test文件:

Hello World\!
abcd 123 张三 !@

示例1:获取文件的行数

wc -l < test
2 # 获取test文件的行数

示例2:逐行读取文件

#!/bin/bash
while read str
do
    echo $str
done < test

这种输入重定向的写法叫做代码重定向

示例3:统计用户在终端输入的文本的单词或数字数量

[ghp@node1 ~]$ wc -w << end
> 1 2 3
> 4\?
> end
4 # -w只统计单词和数字
  • Here Document:Here Document 是 Shell 中的一种特殊的重定向方式,用来将输入重定向到一个交互式 Shell 脚本或程序。

    command << delimiter
        document
    delimiter
    

    它的作用是将两个 delimiter 之间的内容(document) 作为输入传递给 command

    注意:结尾的delimiter 一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和 tab 缩进。开始的delimiter前后的空格会被忽略掉。

    示例:

    cat << EOF
    欢迎来到
    菜鸟教程
    www.runoob.com
    EOF
    
    欢迎来到
    菜鸟教程
    www.runoob.com
    
  • /dev/null 文件:/dev/null 是一个特殊的文件,写入到它的内容都会被丢弃;如果尝试从该文件读取内容,那么什么也读不到。但是 /dev/null 文件非常有用,将命令的输出重定向到它,会起到"禁止输出"的效果。

    command > /dev/null
    

13、文件包含

所谓的“文件包含”是指可以在一个文件中引入其它的文件。比如我们可以在Shell脚本中引用其它脚本文件

. filename   # 注意点号(.)和文件名中间有一空格source filename

示例

脚本一:

#!/bin/bash
name="ghp"

脚本二:

#!/bin/bash

#使用 . 号来引用test1.sh 文件
. ./test1.sh

# 或者使用以下包含文件代码
# source ./test1.sh

echo "我的名字:$name"

执行脚本二

我的名字:ghp

参考资料

  • Shell 教程 | 菜鸟教程 (runoob.com)
  • Shell脚本:Linux Shell脚本学习指南(超详细) (biancheng.net)
  • Shell编程: shell脚本5种执行方式血煞长虹的博客-CSDN博客
  • Shell环境变量set、env、export_訾零的博客-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/16521.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

IPsec中IKE与ISAKMP过程分析(主模式-消息3)

IPsec中IKE与ISAKMP过程分析&#xff08;主模式-消息1&#xff09;_搞搞搞高傲的博客-CSDN博客 IPsec中IKE与ISAKMP过程分析&#xff08;主模式-消息2&#xff09;_搞搞搞高傲的博客-CSDN博客 阶段目标过程消息IKE第一阶段建立一个ISAKMP SA实现通信双发的身份鉴别和密钥交换&…

一文详细介绍查看和启用nginx日志(access.log和error.log),nginx错误日志的安全级别,自定义访问日志中的格式

文章目录 1. 文章引言2. Nginx访问日志(access.log)2.1 简述访问日志2.2 启用Nginx访问日志2.3 自定义访问日志中的格式 3. Nginx错误日志(error.log)3.1 简述错误日志3.2 启用错误日志3.3 Nginx错误日志的安全级别 4. 文末总结 1. 文章引言 我们在实际工作中&#xff0c;经常使…

数字设计小思 - D触发器与死缠烂打的亚稳态

前言 本系列整理数字系统设计的相关知识体系架构&#xff0c;为了方便后续自己查阅与求职准备。在FPGA和ASIC设计中&#xff0c;D触发器是最常用的器件&#xff0c;也可以说是时序逻辑的核心&#xff0c;本文根据个人的思考历程结合相关书籍内容和网上文章&#xff0c;聊一聊D…

函数-函数递归及练习

目录 1、什么是递归&#xff1f; 2、递归的两个必要条件 3、递归的练习 3.1 接受一个整型值&#xff08;无符号&#xff09;&#xff0c;按照顺序打印它的每一位 3.2 编写函数不允许创建临时变量&#xff0c;求字符串的长度 3.3 求第n个斐波那契数 3.4 字符串逆序&…

Go语言-数据结构与算法

go语言之专业数据结构与算法 20.4 稀疏 sparsearray 数组 20.4.1 先看一个实际的需求  编写的五子棋程序中&#xff0c;有存盘退出和续上盘的功能 稀疏数组的处理方法是 : 1) 记录数组一共有几行几列&#xff0c;有多少个不同的值 2) 思想&#xff1a;把具有不同值…

【五一创作】【Midjourney】Midjourney 连续性人物创作 ② ( 获取大图和 Seed 随机种子 | 通过 seed 随机种子生成类似图像 )

文章目录 一、获取大图和 Seed 随机种子二、通过 seed 种子生成类似图像 一、获取大图和 Seed 随机种子 注意 : 一定是使用 U 按钮 , 在生成的大图的基础上 , 添加 信封 表情 , 才能获取该大图的 Seed 种子编码 ; 在上一篇博客生成图像的基础上 , 点击 U3 获取第三张图的大图 ;…

STL常用梳理——VECTOR常用接口及其迭代器实现

Vector篇 Vector介绍Vector实现1、定义默认构造函数使用实现 2、迭代器Iterator迭代器使用 3、空间增长问题使用实现 迭代器迭代器介绍迭代器实现 Vector介绍 vector是STL中容器之一&#xff0c;特性如下&#xff1a; vector是表示可变大小数组的序列容器。就像数组一样&#…

Python基础合集 练习21 (错误与异常处理语句)

‘’‘try: block1 except[ExceptionName]: block2 ‘’’ block1:执行代码,表示可能会出现错误的代码块 ExceptionName: 表示要捕获的异常名称,为可选参数.如果不指定异常名称,则表示捕获所有异常 block2:表示发生异常时执行的代码块 while True: try: num int(input(请输…

设计模式——工厂模式

导航&#xff1a; 【黑马Java笔记踩坑汇总】JavaSEJavaWebSSMSpringBoot瑞吉外卖SpringCloud黑马旅游谷粒商城学成在线设计模式牛客面试题 目录 1、工厂模式介绍 2、披萨项目需求 3、传统方式 4、非静态简单工厂模式 5、静态简单工厂模式 6、工厂方法模式 7、抽象工厂模…

spass modeler

课时1&#xff1a;SPSS Modeler 简介 本课时一共分为五个模块&#xff0c;分别是Modeler概述、工具安装、窗口说明以及功能介绍和应用案例。相信通过本课时内容的学习&#xff0c;大家将会对SPSS Modeler有个基础的了解. 在学习本节课内容之前&#xff0c;先来看看本节课我们究…

目标检测模型量化---用POT工具实现YOLOv5模型INT8量化

POT工具是什么 POT工具&#xff0c;全称&#xff1a;Post-training Optimization Tool&#xff0c;即训练后优化工具&#xff0c;主要功能是将YOLOv5 OpenVINO™ FP32 模型进行 INT8 量化&#xff0c;实现模型文件压缩&#xff0c;从而进一步提高模型推理性能。 不同于 Quantiz…

MYSQL-数据库管理(上)

一、数据库概述 一、数据库基本概念 1.1 数据 1&#xff09; 描述事物的符号记录称为数据&#xff08;Data&#xff09;。数字、文字、图形、图像、声音、档案记录等 都是数据。 2&#xff09;数据是以“记录”的形式按照统一的格式进行存储的&#xff0c;而不是杂乱无章的。…

Mask2Former来了!用于通用图像分割的 Masked-attention Mask Transformer

原理https://blog.csdn.net/bikahuli/article/details/121991697 源码解析 论文地址&#xff1a;http://arxiv.org/abs/2112.01527 项目地址&#xff1a;https://bowenc0221.github.io/mask2former Mask2Former的整体架构由三个组件组成&#xff1a; 主干特征提取器&#xff…

【Java笔试强训 29】

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔&#x1f93a;&#x1f93a;&#x1f93a; 目录 一、选择题 二、编程题 &#x1f525;求正数数…

UNIX环境高级编程——进程关系

9.1 引言 本章详细说明进程组以及会话的概念&#xff0c;还将介绍登录shell&#xff08;登录时所调用的&#xff09;和所有从登录shell启动的进程之间的关系。 9.2 终端登录 9.3 网络登录 9.4 进程组 每个进程除了有一进程ID之外&#xff0c;还属于一个进程组&#xff0c;进…

chatgpt 数据相关应用论文策略简介

hatGPT等预训练大模型&#xff0c;一个核心能力就是经过海量语料的训练加上强化学习的引导&#xff0c;其具有强大的接近人类的文本生成能力。这个能力的一大用途&#xff0c;就是可以为我们生产数据或者标注数据&#xff0c;再基于这些数据训练我们自己的模型。 On the Feasi…

如何让ChatGPT成为科研工作中的小助手?(附使用指南)

大家好&#xff0c;我是带我去滑雪&#xff01; 从2022年年底发布叫ChatGPT的人工智能聊天机器人以来&#xff0c;逐渐强势进入了各行各业&#xff0c;一夜火爆全网&#xff0c;它使用自然语言处理技术来与用户进行交互和沟通&#xff0c;可以回答用户关于知识、娱乐、生活等方…

【计算机专业漫谈】【计算机系统基础学习笔记】W1-计算机系统概述

利用空档期时间学习一下计算机系统基础&#xff0c;以前对这些知识只停留在应试层面&#xff0c;今天终于能详细理解一下了。参考课程为南京大学袁春风老师的计算机系统基础MOOC&#xff0c;参考书籍也是袁老师的教材&#xff0c;这是我的听课自查资料整理后的笔记&#xff0c;…

上市公司碳排放测算数据(1992-2022年)

根据《温室气体核算体系》&#xff0c;企业的碳排放可以分为三个范围。 范围一是直接温室气体排放&#xff0c;产生于企业拥有或控制的排放源&#xff0c;例如企业拥有或控制的锅炉、熔炉、车辆等产生的燃烧排放&#xff1b;拥有或控制的工艺设备进行化工生产所产生的排放。 范…

第十五章 角色移动旋转实例

本章节我们创建一个“RoleDemoProject”工程&#xff0c;然后导入我们之前创建地形章节中的“TerrainDemo.unitypackage”资源包&#xff0c;这个场景很大&#xff0c;大家需要调整场景视角才能看清。 接下来&#xff0c;我们添加一个人物模型&#xff0c;操作方式就是将模型文…