【Linux】Shell脚本编程(十一)

Shell基本概念

Shell基本概念

Shell脚本是一种用来自动执行一系列命令的文本文件(批处理)。它们通常包含了像命令行中输入的那样的命令(交互式)。Shell脚本的语法是由Shell解释器来解释执行的,它允许你编写一系列命令以完成特定的任务。

基本的Shell脚本语法包括:

  • 命令:Shell脚本可以包含一系列的命令,每个命令占据一行,可以是系统命令或者自定义函数。
  • 注释:以 # 开头的行表示注释,用于解释脚本的功能或者提供说明。
  • 变量:用于存储数据或者命令的结果,在使用时需要使用 $ 符号进行引用。
  • 控制结构:包括条件语句(if-else)、循环语句(for、while、until)、case语句等,用于根据条件或者循环执行不同的命令。
  • 函数:允许你将一组命令封装在一个可调用的单元中,以便多次重用。

常见的shell有bash(Bourne Again SHell)、sh(Bourne Shell)、csh(C Shell)、ksh(Korn Shell)等。其中,bash是最流行和常用的Shell之一,它是Linux和macOS系统中默认的Shell。

  • bash: 是GNU项目的一部分,它是Bourne Shell的增强版本,提供了更多的功能和特性,包括命令行编辑、命令历史、条件测试、循环结构等。
  • sh: 是Unix系统中的原始Shell,通常指的是Bourne Shell。它比较简单,功能相对较少,但在一些资源受限的系统中可能会用到。
  • csh: C Shell,其语法和功能受到C语言的影响,提供了类似C语言的语法特性,如变量的赋值和引用方式。
  • ksh: Korn Shell,是由AT&T Bell实验室的David Korn开发的Shell,它继承了sh和csh的一些特性,提供了更强大的功能和更友好的用户体验。

要创建和运行一个简单的Shell脚本,你需要按照以下步骤进行:

  1. 创建一个新的文本文件,使用任何文本编辑器,如**vimnanogedit**等。
  2. 在文件中编写Shell脚本代码,包括你想要执行的命令、变量赋值、控制结构等。
  3. 保存文件时,使用 .sh 扩展名来表示这是一个Shell脚本文件,例如 hello**.sh**。
  4. 在命令行中使用 chmod 命令给脚本文件添加执行权限,例如 chmod u+x myscript.sh
  5. 使用 ./ 加上脚本文件名来运行脚本,例如 ./hello.sh

例如,一个简单的Shell脚本示例(hello.sh)如下:

#!/bin/bash
# 这是一个简单的Shell脚本示例

# 定义一个变量
NAME="Hello, World!"

# 输出欢迎消息
echo "$NAME"

# 在终端命令行中输入: 
# $ chmod u+x hello.sh
# $ ./hello.sh

# 输出结果:
# $ Hello, World!

通常一个Shell脚本会在顶部包含一些注释消息,以表明使用的shell解释器类型,脚本名称,脚本作者,脚本制作或修改时间,脚本功能。为了养成一个良好的习惯以便后续排查,在大型脚本中可以添加类似注释。

#!/bin/bash
# Script Name: hello.sh
# Author: xxx
# Time: 2024-04-01
# Function: 在终端中输出Hello, World!

在 Linux 系统中,执行 shell 脚本可以通过多种方式,不仅仅局限于 ./ ,常见的执行方式有两种:直接通过路径执行和使用 bash 或其他 shell 明确执行。两者的区别主要在于环境设置、执行权限、和解释器选择。

  1. 直接通过路径执行

当你直接通过脚本的路径来执行(例如,./script.sh/path/to/script.sh),操作系统会查看脚本文件的第一行,通常是 shebang(#!)行,来确定应该使用哪个解释器来执行脚本。例如:

#!/bin/bash
echo "Hello, world!"

在这个例子中,#!/bin/bash 告诉系统使用 /bin/bash 来运行脚本。这意味着无论当前的默认 shell 是什么,脚本都会用 Bash 来执行。

2. 使用 bash 执行

另一种方式是直接使用特定的 shell 来执行脚本,如 bash script.sh。这种方法不需要脚本文件具有执行权限,因为你是通过 shell 直接调用解释器来执行脚本文件中的代码。在这种情况下,shebang 行被忽略,因为已经明确指定了解释器。这意味着,即使 shebang 行指定了另一个解释器,如 /bin/sh/bin/zsh,脚本也会在 bash 环境下执行。


变量与数据类型

了解基本概念

  1. 什么是变量?
    • 当我们谈论变量时,无论是在 Linux 系统中还是在计算机编程中,都指的是一个用于存储和表示数据的符号名称。变量可以存储各种类型的数据,如数字、文本、对象引用等,并且可以在程序执行过程中被赋予不同的值。linux中常见的有用户变量、环境变量、特殊变量三种。
  2. 为什么在 Linux 系统中使用变量?
    • 存储数据:变量允许程序和系统存储和管理各种类型的数据,包括数字、字符串、字符串列表等。
    • 传递信息:变量可以用于传递信息,允许不同部分的程序或系统之间共享数据。
    • 控制程序行为:变量可以用于控制程序的行为,例如条件语句中使用变量来决定程序的分支。
    • 简化代码:通过使用变量,可以将重复使用的值存储在一个位置,从而减少代码重复,并提高代码的可读性和可维护性。
    • 增加灵活性:通过修改变量的值,可以改变程序的行为或系统的设置,从而增加系统的灵活性和可配置性。
    • 支持自动化和脚本编程:在脚本编程中,变量是非常重要的,它们允许我们将数据存储在一个位置,并在脚本的不同部分重复使用,从而简化代码并提高可重用性。

变量的定义与赋值

  1. 如何定义一个变量?

    • 在 Shell 中,可以使用等号=来定义一个变量。
    VAR=value
    VAR='v a l u e'
    VAR="$(pwd) value"
    
    # 错误示例
    VAR = value    # = 单侧或两侧有空格
    "VAR=value"
    'VAR=value'
    VAR=v a l u e  # 变量值带空格可能会出现意想不到的错误
    
    

    其中,VAR 是变量的名称,而 value 是要赋给变量的值。

    变量名可以包含字母、数字和下划线(_),但不能以数字开头或者跟命令、关键字重名。

    在Shell中变量名是区分大小写的。变量值一般情况下是不能带空格的,但可以在引号中使用空格。

    建议使用大写字母来命名环境变量,而使用小写字母来命名本地变量,以便于区分。

    若是不想被别人修改这个变量,可以使用readonly这个关键字。

    readonly VAR=value
    VAR="test" # 报错
    unset VAR  # 报错
    
    • 设置只读变量后如何取消

      1. 重新声明变量: 您可以在代码中找到变量的声明,并将其从只读变量重新声明为可写变量。这样做会改变变量的属性,使其可以被修改。但是请注意,这可能会导致程序中其他地方的行为出现意外。
      2. 使用拷贝变量: 您可以创建一个新的变量,并将只读变量的值赋给它。这样,您就可以使用新变量来进行修改操作,而不会影响原始的只读变量。
    • 除了使用=来为变量赋值,我们还可以使用read 命令以交互的方式主动向变量赋值。

    read 命令在 Bash 和其他 shell 脚本中用于从标准输入(键盘)或其他文件描述符中读取一行数据。它通常用于脚本中,以获取用户输入的信息或处理文本数据。

    # 用提示符要求用户输入,并将输入的数据存储在变量中
    read -p "请输入您的名字: " name
    echo "欢迎,$name!"
    
    # 读取密码,不在屏幕上显示输入的字符
    read -sp "请输入密码: " password
    echo "密码已接收。"
    
    # 使用 -r 选项读取一行数据,包括反斜杠
    read -r line
    echo "您输入了: $line"
    
    # 读取多个值到不同变量
    read -p "请输入您的名字和姓氏: " firstname lastname
    echo "您的全名是:$firstname $lastname"
    
    # 从文件中逐行读取内容
    while IFS= read -r line
    do
      echo "文件行:$line"
    done < "filename.txt"
    
    # 示例所用选项介绍:
    # -p:指定读取输入前显示的提示符。
    # -s:使输入的数据不回显在终端上,常用于敏感信息的输入,如密码。
    # -r:不允许反斜杠字符 (\) 转义下一个字符,这是处理文本输入的推荐方式,以防止脚本意外解释反斜杠
    

    使用read命令时需要注意的事项:

    • 如果在脚本中使用 read 命令,而脚本是通过非交互方式(如通过管道或重定向)调用的,read 会立即结束,因为它不会等待输入。

    • 使用 s 选项时要注意,虽然输入不会显示在终端上,但仍可能被进程监视工具捕捉。

    • 在处理文件数据时使用 read -r 以防止脚本错误解释含反斜杠的行。

    • 在使用 read 命令读取数组时,确保 IFS(内部字段分隔符)正确设置,以便正确分割输入的数据。

    • 内部字段分隔符IFS 环境变量

      IFS 是一个环境变量,用于指定Shell 在读取输入(如命令行参数或文件内容)时,如何根据特定的分隔符将输入分割成多个字段。 默认情况下,IFS 包含三个字符:空格、制表符(tab)和换行符(newline)。 这意味着Shell 默认会根据这些字符来分割文本。

  2. 如何取消一个已定义的变量?

    通常使用unset来取消定义变量,但不能取消只读变量。

    VAR=value
    unset VAR
    
  3. 如何给变量重新赋值?

    给变量赋值可以通过使用等号 = 来实现。注意,只读变量不能被重新赋值。

    NAME="John"
    AGE=30
    

    这样就分别给 NAMEAGE 这两个变量赋了值。

    猜想一下如果访问未初始化的变量名会怎么样?

  4. 如何在 Shell 中访问变量?

    可以使用 $ 符号加上变量名 或者 ${变量名}

    NAME="John"
    NAME="${NAME} White"
    echo $NAME  #John White
    

    在某些特殊情况下,花括号访问的形式会更准确。

    # 以下这两个效果是完全不同的
    $test01
    ${test}01
    

环境变量

  1. 什么是环境变量?

    环境变量是在 Shell 运行时可用的变量,对整个系统或用户环境都是全局性的。它们通常用于存储系统配置信息、用户偏好设置以及其他重要的参数。环境变量在 Shell 启动时被设置,并在整个 Shell 会话中保持不变,直到 Shell 退出或被重新设置。

  2. 如何设置环境变量?

    可以使用 export 命令来设置环境变量。

    export VARIABLE_NAME=value
    

    这样就将一个变量定义为环境变量,并为其赋值。设置后,该环境变量将在当前 Shell 会话中可用,并且在子进程中也会被继承。(如需永久更改,需要配置文件~/.bashrc,谨慎更改,注意做好备份)

  3. 全局环境变量和局部环境变量的区别是什么?

    全局环境变量是在 Shell 启动时设置的,对整个系统或用户环境都是全局性的。它们可以被所有的 Shell 进程以及由 Shell 启动的子进程所访问。

    局部环境变量是在当前 Shell 会话中设置的,只在当前 Shell 会话中有效,不会被子进程继承。

    简而言之,全局环境变量对整个系统或用户环境都是全局性的,而局部环境变量只在当前 Shell 会话中有效。

  4. 常见的系统环境变量有哪些?

    • PATH:用于指定系统在哪些目录中查找可执行程序。
    • HOME:指定用户的主目录。
    • USER:指定当前登录用户的用户名。
    • SHELL:指定当前使用的 Shell 程序的路径。
    • LANGLC_*:用于指定系统的语言环境设置。
    • PWD:指定当前工作目录的路径。

    这些环境变量在系统中具有重要作用,通常由系统在启动时设置,但用户也可以根据需要自行修改。

  5. 如何在不同的环境中传递变量?

    • 导出环境变量:使用 export 命令将变量导出为环境变量,使其在子进程中可用。

      export MY_VARIABLE="value"
      
    • 使用配置文件:可以将变量存储在配置文件中,然后在不同的环境中加载相应的配置文件。

      # 在脚本中加载配置文件,**config.sh** 文件包含了自己需要的变量定义
      source config.sh
      
    • 通过位置参数传递:可以将变量作为脚本的参数,在不同的环境中调用脚本并传递不同的值。

变量的范围

  1. 变量的作用域是什么?

    变量的作用域指的是变量在程序中可见和可访问的范围。在编程语言中,变量的作用域可以分为局部作用域和全局作用域。

  2. 局部变量和全局变量的区别是什么?

    局部变量是在特定的代码块或函数内部定义的变量,只在该代码块或函数内部可见和可访问。一旦超出了其定义的范围,局部变量就不再存在。

    全局变量是在整个程序中定义的变量,可以在程序的任何位置使用。全局变量在定义后一直存在,直到程序结束或显式地被删除。

变量中常用的各种符号

普通字符:通常指的是没有特殊含义的字符。这些字符在解释或执行时被视为它们字面上的意思,而不是执行某种特定的命令或操作。

元字符(有特定的功能,用于控制命令的执行流程或者行为,格式化命令,或者调整其输出)

符号格式含义
;命令1 ; 命令2顺序执行命令,命令1执行完毕后,无论成功与否,立即执行命令2。
&&命令1 && 命令2条件执行命令,只有当命令1成功执行(返回值为0)后,才会执行命令2。
&命令 &将命令作为后台进程执行,并且立即返回命令提示符,不阻塞终端
\\特殊符号使后面的一个特殊符号变为普通字符。
‘’‘内容’将单引号内的所有字符视为普通字符,特殊字符失去其特殊含义。
“”“内容”双引号内的普通字符保持不变,特殊字符如变量和命令替换可以生效。
() {}(内容) {内容}命令组合符,可以将多个命令组合在一起执行,也可以将多个字符串组合成字符串列表。注意括号内两端有空格。组合的目的是对这些命令进行统一的操作,如管道、后台运行、输入输出重定向。
$()$(命令)执行括号中的命令,并将输出结果插入到当前命令行。支持嵌套使用。
# ; 顺序执行两个命令:
# 这会先输出 Hello,然后无论成功与否,接着输出 World。
echo "Hello"; echo "World"

# && 条件执行,仅当第一个命令成功时执行第二个命令:
# 如果 mkdir命令成功执行成功,则会继续执行 echo命令
mkdir new_folder && echo "Folder created successfully"

# || 仅当第一个命令失败时执行第二个命令:
# 如果cd命令执行失败,将继续执行echo命令
cd nonexistent_directory || echo "Directory does not exist"

# & 在后台执行命令:
# 这会在后台执行 sleep 10 命令,立即返回命令提示符,不阻塞终端。
sleep 10 &

# \ 转义特殊字符:
# 这里使用 \ 来保持双引号在字符串中的字面意义。输出结果:"Hello"
echo "\"Hello\""

# '' 保留单引号内的所有字符的字面意义:
# 输出将是字面上的含义。输出结果:\"Hello\"
echo '\"Hello\"'

# "" 在双引号中,特殊字符能发挥作用:
# 这将展开 `$HOME` 变量,显示如 "Your home directory is /your/home/path"。
echo "Your home directory is $HOME"

# () 命令组合,执行多个命令:
# 将echo命令和cat命令执行的结果一同重定向到test文件中
( echo "Hello, this is test file!" ; cat file ) > test

# $() 命令替换,执行命令并使用其输出:
# 这将输出当前日期和时间,如 "The date is Sun Apr 15 12:00:00 UTC 2024"。
echo "The date is $(date)"

组合命令符 (){} 之间的区别:

pwd
# /home/test

{ cd ~/code ; pwd ; }   # 最后一个 ; 不可省略
# /home/test/code

pwd
# /home/test/code
# 本shell进程的当前目录已经改变
# {} 命令组合符是用当前进程来执行的
pwd
# /home/test

( cd ~/code ; pwd ; )   # 最后一个 ; 可以省略
# /home/test/code      # 子进程的目录已经改变

pwd
# /home/test
# 本shell进程的当前目录没有改变
# () 命令组合符是用生成的子进程来执行的

数据类型

  1. 字符串

    字符串是Shell脚本中最常见的数据类型,用于表示文本信息。字符串可以由单引号、双引号或不使用引号来表示。其中,单引号包裹的字符串中的特殊字符不会被解释,而双引号包裹的字符串中的特殊字符会被解释。

    # 单引号字符串
    str1='Hello, World!'
    
    # 双引号字符串
    str="Hello, World!"
    

    常用的字符串操作方法:

    • 获取字符串长度,使用${#string}语法
    # 获取字符串长度
    LENGTH=${#STRING1}
    
    • 字符串截取,使用${string:start:length}语法
    # 字符串截取
    substr=${str:0:5}  # 从索引0开始截取5个字符
    
    echo ${str: -2}  # 从倒数第二个字符开始提取直到末尾的子串
    

    其中,start是起始位置,length是要截取的字符数。如果length被省略,则截取到字符串的末尾。如果length超过字符串长度,则按最大字符串长度处理。

    在Bash 4.2及更高版本中,你可以使用负数作为**start参数来从字符串的末尾开始计数。注意:为了使用负数索引,你必须在start**前放置一个空格,以避免与默认值的混淆。

    使用bash --version 命令可查看Bash版本号。

    • 字符串替换,使用${var/search/replace}语法
    new_str=${str/Bash/World}  # 将第一个匹配项替换为"World"
    

    如果省略**replace,则会删除第一个匹配项。如果要替换所有匹配项,可以使用//**。

    • 字符串拼接,使用${var1}${var2}或者${var1}text${var2}
    str1="a"
    str2="c"
    combined_str1="${str1}${str2}"    # ac
    conbined_str2="${str1} b ${str2}" # a b c
    
  2. 数值

    在Shell脚本中,数字通常是无符号整数,可以直接进行数学运算。需要注意的是,Shell脚本中的数字类型没有区分整数和浮点数的概念。

    既然提到到了数值,那么肯定也有数值运算,这时我们就可以使用expr来进行数学运算。

    它的通用格式是:expr 数值1 运算符 数值2

    支持的运算符如下:

    + - * / % & | == != < > <= >=

    # 使用 expr 进行数学运算
    NUM1=10
    NUM2=5.5
    SUM=$(expr $NUM1 + $NUM2)
    echo "Sum is $SUM"
    

    expr命令的返回值暂不做整理

    注意,数值的本质其实也是字符串,数值也能使用字符串的操作方法。

  3. 字符串列表

    字符串列表是一组按照顺序排列的相同类型的数据集合,在Shell脚本中用于存储多个值。字符串列表的索引从0开始。使用圆括号来定义字符串列表,并通过索引来访问字符串列表元素。for-in循环可以遍历字符串列表。

    # 使用命令组合符 () 定义字符串列表
    arr=("apple" "banana" "orange")
    
    # 使用索引访问字符串列表元素
    echo "${arr[1]}"  # 输出:banana
    echo "$arr[0]"    # 输出:apple[0]
    
    # 遍历字符串列表
    for fruit in "${arr[@]}"
    do
      echo $fruit
    done
    
    # apple
    # banana
    # orange
    
  4. 空值

    在Shell脚本中,变量未赋值时,其值为空。可以通过 unset 命令将变量的值设置为空。

    VAR=value
    unset VAR
    echo VAR
    
    # 输出结果
    # 
    

函数与脚本参数、返回值

函数的基本概念

函数指的是一段被命名的、可重复调用的代码块。在Shell脚本中,函数是一种组织代码的方式,允许你将一系列相关的命令和操作封装在一起,并为其指定一个名称。这样做有助于提高代码的可读性、可维护性和重用性。

在Shell脚本中,定义一个函数的语法如下:

function_name () {
    # 函数体,包含一系列命令或操作
    # 可以使用传递给函数的参数,以$1、$2、$3...的形式访问
}

# xxx
# xxx
# xxx

function_name # 调用函数
  • function_name是自定义的变量名,它和变量的命名规则一样,只能以数字、下划线、字母命名,且开头不能是数字,而且不能与关键字重名。
  • 一旦你定义了一个函数,就可以在脚本的其他部分调用它,直接输入函数名即可实现函数功能。

示例:

welcome () {
    echo "Welcome to Shell scripting!"
}

# xxx
# xxx
# xxx

welcome  # Welcome to Shell scripting!

在其他脚本中使用某个脚本中的函数

# 使用source导入脚本(包含指定函数的脚本)
source /path/to/script/welcome.sh

# 调用脚本welcome中定义的函数
welcome  # Welcome to Shell scripting!

在此不做函数参数的介绍

脚本位置参数(特殊变量)

当你在命令行中执行一个脚本时,你可以向它传递一系列的参数,这些参数在脚本中被自动分配到位置参数中。

  • $0 :是当前 Shell 脚本程序的名称,包括路径(如果有的话)

    如果你有一个名为 myscript.sh 的脚本,执行命令 ./myscript.sh arg1 arg2,那么 $0 的值将是 ./myscript.sh。

  • $#:是参数的数量(不包括$0)

    如果你执行脚本 ./myscript.sh arg1 arg2,那么 $# 的值将是 2,因为有两个位置参数。

  • $1、$2…:是脚本被调用时分别对应的参数值,参数超过9以后需要花括号${10}

    如果你执行脚本 ./myscript.sh arg1 arg2,那么 $1 的值将是 arg1,$2 的值将是 arg2。

  • $*:记录了命令行的整个参数(不包括$0),参数之间以空格为分隔

  • $@:记录了命令行的各个参数(不包括$0),参数之间以特殊的分隔符分割

  • $$:记录了本名林的执行进程的进程号PID。

    进程等到之后的进程管理章节再做整理。

这样说 $*$@ 和字符串列表有些云里雾里,那么该如何区分 $*$@ 呢?

可以通过示例来深入理解它们两者之间的异同:

# 为hello.sh脚本传入 Hello 和 World 两个位置参数
./hello.sh Hello World

echo "$*"        # 输出结果:Hello World
echo "$@"         # 输出结果:Hello World

# 遍历所有参数并逐个输出
for arg in "$@"; do
    echo "$arg"
done

# 输出结果:
# Hello
# World

for arg in "$*"; do
    echo "$arg"
done

# 输出结果:
# Hello World

# 以下这两种输出结果是一样的,是因为IFS的原因
for arg in $@; do
    echo "$arg"
done

# 输出结果:
# Hello
# World

for arg in $*; do
    echo "$arg"
done

# 输出结果:
# Hello
# World

在linux中,不仅有位置参数,还有位置参数移动命令。想要修改位置参数的值,只需要使用 shift 命令。

shift 命令在 Bash 和其他 shell 脚本中用于移动位置参数。每次调用 shift,位置参数(不包括$0)都会向左移动,这意味着 $2 的值会移到 $1$3 的值移到 $2,依此类推。这个命令常用于处理传递给脚本的参数,尤其是在参数数量未知或需要逐个处理参数时。

它之后可以跟一个可选的数字,shift [n] ,这个数字是要移动的位置数。如果不指定,默认为 1。

# 一个处理任意数量参数的示例
while [ "$#" -gt 0 ]; do
  echo "处理参数: $1"
  shift
done

# 使用 shift 移动两个位置
while [ "$#" -gt 0 ]; do
  echo "当前参数: $1"
  shift 2
done

# 在脚本中逐步移除参数并处理剩余参数
echo "原始参数:$@"
shift 3  # 移除前三个参数
echo "移除后剩余参数:$@"

注意,一旦使用 shift 命令时,传入的参数将被移除,就无法恢复这些参数。如果需要在后续操作中再次访问原始参数,应事先将其存储或复制。并且移动的参数数量不应超过实际传递的参数数量,否则会导致错误。通常,在使用 shift 前会检查 $#(参数数量)以确保操作的安全。

使用 shift 命令后,除了 $0 之外,$1$2…$*$@ 的值都会被更改。

除了在执行脚本时传入位置参数,我们还可以通过命令 set 来强制设定位置参数。

#!/bin/bash
echo "原始参数: $*"
set a b c
echo "新设置的参数: $1 $2 $3"  # 新设置的参数:a b c

这个脚本首先打印原始传入的参数,然后将位置参数重置为 abc

脚本返回值

Shell脚本的返回值是一个整数值,用于指示脚本或命令的执行结果。一般而言,退出状态码为0表示运行成功,非零值表示运行失败。

在可以使用 exit 命令来设置退出状态码。语法为 exit [n],其中 n 是要设置的退出状态码。如果省略 n,则默认使用最后一个命令的退出状态码。在Linux中,每条命令执行后,都会有一个状态码来判断是否执行成功。

$?对应的是显示上一次命令的执行返回值,在Shell脚本中,返回值是一个整数值,用于指示脚本或函数的执行结果。通常,0表示成功,非零值表示错误。

如果你执行了一个命令 ls,然后通过 $? 获取上一次命令的返回值。如果 ls 命令执行成功,返回值将是 0,否则返回值将是一个非零值,表示错误。

# 执行一个命令
ls

# 检查上一次命令的返回值
if [ $? -eq 0 ]; then
    echo "命令执行成功"
else
    echo "命令执行失败"
fi

# 退出脚本
exit 0

条件表达式与控制流

条件表达式

条件测试表达式在shell脚本中用于根据条件的真假执行不同的命令。它们通常用于if语句、while循环等控制结构中,用于决定代码的执行流程。条件测试语句使用方括号 [ ] 或者 [[ ]] 来表示,包含了一个条件表达式,根据表达式的真假来确定执行的命令。

基本结构

# 基本结构一
if [ condition ]; then
    # commands if condition is true
fi

# 基本结构二
if [[ condition ]]; then
    # commands if condition is true
fi

其中,condition 是一个用于判断真假的表达式,可以是各种比较表达式、逻辑测试表达式等的组合,各个表达式之间可以嵌套使用。

注意,在shell脚本中“执行正确”、“真”、“true”一般是指执行命令后返回的状态码为0,这与c语言的不一样。

常见判断真假的表达式分为四类:文件判断、字符串比较、数值比较、逻辑测试。

  1. 文件测试:用于检查文件的属性,如是否存在、是否可读可写等。

    文件判断描述
    -e file如果文件存在,则为真
    -f file如果文件存在且是普通文件,则为真(File)
    -d file如果文件存在且是目录,则为真(Directory)
    -s file如果文件存在且大小不为零,则为真
    -r file如果文件存在且可读,则为真(Read)
    -w file如果文件存在且可写,则为真(Write)
    -x file如果文件存在且可执行,则为真(eXecute)
    -L file如果文件存在且为符号链接,则为真(Link)
    file1 -nt file2如果file1比file2新(修改时间),则为真(Newer Than)
    file1 -ot file2如果file1比file2旧(修改时间),则为真(Older Than)
    -O file如果文件存在且属于当前用户,则为真(Owner)
    -G file如果文件存在且其所属组与当前用户相同,则为真(Group)
    -C file如果文件存在且已经压缩,则为真(Compress)
    #!/bin/bash
    
    # 检查文件是否存在并且可读
    if [ -r "example.txt" ]; then
        echo "文件 example.txt 存在并且可读"
    else
        echo "文件 example.txt 不存在或不可读"
    fi
    
    # 检查文件是否存在并且可写
    if [ -w "example.txt" ]; then
        echo "文件 example.txt 存在并且可写"
    else
        echo "文件 example.txt 不存在或不可写"
    fi
    
    # 检查文件是否存在并且非空
    if [ -s "example.txt" ]; then
        echo "文件 example.txt 存在并且非空"
    else
        echo "文件 example.txt 不存在或为空"
    fi
    
  2. 字符串比较:用于检查字符串的内容、长度等属性。

    字符串比较描述
    str1 = str2如果str1等于str2,则为真;注意这个不是==
    str1 != str2如果str1不等于str2,则为真
    -z str如果str长度为零,则为真
    -n str如果str长度不为零,则为真
    str如果str不为空,则为真(与-n str等价)
    #!/bin/bash
    
    str1="Hello"
    str2="World"
    
    # 检查字符串是否相等
    if [ "$str1" = "$str2" ]; then
        echo "字符串相等"
    else
        echo "字符串不相等"
    fi
    
    # 检查字符串是否为空
    if [ -z "$str1" ]; then
        echo "字符串为空"
    else
        echo "字符串不为空"
    fi
    
    # 检查字符串长度是否大于0
    if [ -n "$str2" ]; then
        echo "字符串长度大于0"
    else
        echo "字符串长度等于0"
    fi
    
  3. 数值比较:用于检查数值之间的大小关系。

    数值比较描述
    n1 -eq n2如果n1等于n2,则为真(Equal)
    n1 -ne n2如果n1不等于n2,则为真(Not Equal)
    n1 -gt n2如果n1大于n2,则为真(Greater Than)
    n1 -lt n2如果n1小于n2,则为真(Less Than)
    n1 -ge n2如果n1大于等于n2,则为真(Greater than and Equal)
    n1 -le n2如果n1小于等于n2,则为真(Less than and Equal)
    #!/bin/bash
    
    num1=10
    num2=20
    
    # 检查数值是否相等
    if [ "$num1" -eq "$num2" ]; then
        echo "数值相等"
    else
        echo "数值不相等"
    fi
    
    # 检查数值是否大于
    if [ "$num1" -gt "$num2" ]; then
        echo "$num1 大于 $num2"
    else
        echo "$num1 不大于 $num2"
    fi
    
    # 检查数值是否小于等于
    if [ "$num1" -le "$num2" ]; then
        echo "$num1 小于等于 $num2"
    else
        echo "$num1 大于 $num2"
    fi
    
  4. 逻辑测试:用于检查逻辑的真假。

    逻辑测试描述
    expr1 -a expr2如果expr1和expr2都为真,则为真(And 或者 && )
    expr1 -o expr2如果expr1或expr2有一个为真,则为真(Or 或者
    ! expr如果expr为假,则为真
    #!/bin/bash
    
    var1=10
    var2=20
    
    # 逻辑与
    if [ "$var1" -gt 0 -a "$var2" -gt 0 ]; then
        echo "两个变量均大于0"
    else
        echo "至少有一个变量不大于0"
    fi
    
    # 逻辑或
    if [ "$var1" -eq 0 -o "$var2" -eq 0 ]; then
        echo "至少有一个变量等于0"
    else
        echo "两个变量均不等于0"
    fi
    
    # 逻辑非
    if [ ! "$var1" -eq "$var2" ]; then
        echo "两个变量不相等"
    else
        echo "两个变量相等"
    fi
    

控制流

控制流是指shell程序执行时代码的执行顺序。在执行程序时,程序会根据不同的条件选择不同的执行路径。这些路径可以是顺序执行、根据条件执行或者循环执行。

Linux中常见的控制流结构语句有:条件语句,循环语句,分支语句。

  • 条件语句(if-else):条件语句根据给定的条件来执行不同的代码块。如果条件为真,则执行if语句块中的代码,否则执行else语句块中的代码。
  • 循环语句(for、while):循环语句用于重复执行一段代码,直到达到特定条件为止。for循环会在指定的次数内重复执行代码,而while循环会在条件为真时重复执行代码,直到条件为假为止。
  • 分支语句(case):分支语句根据不同的条件执行不同的代码块。它类似于if-else语句,但更适用于多个条件的情况,代码更清晰易读。

上述三种语句可以互相嵌套,以此完成灵活、复杂的功能。

  1. 条件语句

    用于根据给定条件来执行不同的代码块。在Linux中,条件语句通常用于Shell脚本中,用于编写各种自动化任务、系统管理脚本等。

    if-else条件语句的基本结构如下:

    if [ expr1 ]; then
        # 条件1成立时执行的代码块
    elif [ expr2 ]
        # 条件1不成立,条件2成立时执行的代码块
    else
        # 上述所有条件不成立时执行的代码块
    fi
    
    • if [ expr1 ]:条件用于评估是否为真。条件可以是文件判断表达式、字符串比较表达式、数值比较表达式或逻辑测试表达式等。条件两端需要有空格,[] 之间也需要有空格。
    • then:表示条件成立时执行的代码块的开始。
    • elif [ expr2 ]:可选部分,当上文条件不满足时,继续根据判断后续条件是否满足。
    • else:可选部分,表示上文条件全部不成立时执行的代码块的开始。
    • fi:表示条件语句结束。

    注意事项:

    • 条件语句中的变量需要使用双引号引起来,以防止空值或包含空格的变量引起的问题。
    • 在条件语句中使用 [] 时,注意空格的使用。
    • 条件语句中的条件支持各种逻辑运算符,可根据需要组合条件判断。

    示例一:通常用法

    #!/bin/bash
    
    # 定义一个变量
    age=20
    
    # 判断年龄是否大于等于18岁
    if [ $age -ge 18 ]; then
        echo "成年人"
    else
        echo "未成年人"
    fi
    

    示例二:多条件判断用法

    #!/bin/bash
    # 使用elif
    
    score=85
    
    if [ $score -ge 90 ]; then
        echo "成绩优秀"
    elif [ $score -ge 80 ]; then
        echo "成绩良好"
    elif [ $score -ge 70 ]; then
        echo "成绩中等"
    elif [ $score -ge 60 ]; then
        echo "成绩及格"
    else
        echo "成绩不及格"
    fi
    
    #!/bin/bash
    # 使用逻辑测试表达式
    
    # 定义一个变量
    age=15
    grade="A"
    
    # 判断年龄大于等于18岁并且成绩为A
    if [ $age -ge 18 ] && [ "$grade" = "A" ]; then
        echo "成绩优秀"
    else
        echo "成绩不够优秀"
    fi
    
    

    示例三:嵌套条件语句

    #!/bin/bash
    
    # 定义两个变量
    num1=10
    num2=20
    
    if [ $num1 -gt 0 ]; then
        echo "num1 是正数"
        if [ $num2 -gt 0 ]; then
            echo "num2 也是正数"
        else
            echo "num2 不是正数"
        fi
    else
        echo "num1 不是正数"
    fi
    
  2. 分支语句

    分支语句(case 语句)用于根据不同的条件执行不同的代码块,通常被视为是条件语句的一种。

    case语句的基本结构:

    case 表达式 in
        模式1)
            # 如果表达式匹配模式1,则执行的代码块
            ;;
        模式2)
            # 如果表达式匹配模式2,则执行的代码块
            ;;
        ...
        *)
            # 如果表达式不匹配任何模式,则执行的代码块
            ;;
    esac
    
    • case 表达式 in:开始分支语句,并指定要匹配的表达式。
    • 模式1)模式2) 等:各个模式用来匹配表达式的值,每个模式后面需要跟着一个 )
    • ;;:表示该模式下的代码块执行完毕,用于分隔不同的模式,注意不要遗漏。
    • *):通配符模式,用于处理表达式不匹配任何模式时的情况,即默认情况。
    • esac:结束分支语句。

    示例:case语句的简单使用

    #!/bin/bash
    
    day="Monday"
    
    case $day in
        Monday | Mon) # 使用 | 可以选择多个
            echo "星期一"
            ;;
        Tuesday)
            echo "星期二"
            ;;
        Wednesday)
            echo "星期三"
            ;;
        Thursday)
            echo "星期四"
            ;;
        Friday)
            echo "星期五"
            ;;
        *)
            echo "其他星期"
            ;;
    esac
    
  3. 循环语句

    循环语句用于重复执行一段代码,直到满足指定条件为止。常见的循环语句有 forwhileuntil。注意,循环也是可以嵌套的。

    • for 循环用于迭代一个数组中的元素,执行指定的代码块。
    for 变量 in 数组
    do
        # 执行的代码块
    done
    

    示例:for的使用

    #!/bin/bash
    
    # 打印数组中的元素
    fruits=("apple" "banana" "orange")
    
    for fruit in "${fruits[@]}"
    do
        echo "水果: $fruit"
    done
    
    • while 循环在条件为真时重复执行一段代码块。
    while 条件
    do
        # 执行的代码块
    done
    

    示例:while的简单使用

    #!/bin/bash
    
    # 使用while循环打印数字1到5
    count=1
    
    while [ $count -le 5 ]
    do
        echo "Count: $count"
        count=$((count + 1))
    done
    
    • until 循环在条件为假时重复执行一段代码块,直到条件为真为止,与while刚好相反
    until 条件
    do
        # 执行的代码块
    done
    

    示例:

    #!/bin/bash
    
    # 使用until循环打印数字1到5
    count=1
    
    until [ $count -gt 5 ]
    do
        echo "Count: $count"
        count=$((count + 1))
    done
    
    • 使用 break 语句来立即跳出循环,终止循环,不进行后续的条件判断。

    • 使用 continue 语句跳过当前循环的剩余代码,直接进入下一次循环,继续进行条件判断。

    • 循环与文件处理

    循环结构在文件处理中特别有用。可以使用 for 循环遍历文件中的每一行

    #!/bin/bash
    
    # 使用for循环遍历文件中的每一行
    file="example.txt"
    
    for line in $(cat "$file")
    do
        
        echo "$line"
    done
    
    
    while IFS= read -r line
    do
      echo "Line: $line"
    done < example.txt
    
    # 这里,IFS= (input field separator) 确保读取行时不会忽略行首的空白字符。
    # -r 选项防止 read 命令解释反斜杠字符。
    

正则表达式与通配符

什么是正则表达式

正则表达式(Regular Expression),通常缩写为正则或 regex,是一种用于描述字符串匹配模式的表达式。正则表达式提供了一种强大且灵活的文本搜索和替换的方式,它可以用于在文本中搜索特定模式的字符串、验证输入的格式是否符合预期,以及进行字符串的分割和替换等操作。

正则表达式由普通字符(例如字母、数字、标点符号等)和元字符(特殊字符)组成,通过组合这些字符和元字符形成一个模式,用于匹配目标字符串中符合该模式的部分。

基础正则表达式

  1. ^:匹配行的开头。
  2. $:匹配行的结尾。
  3. .:匹配任意单个字符,除了换行符。
  4. *:匹配前一个字符的零个或多个副本。
    • a*:匹配零个或多个连续的字母 ‘a’
  5. +:匹配前一个字符的一个或多个副本。
    • a+:匹配一个或多个连续的a
  6. ?:匹配前一个字符的零个或一个副本。
    • a?:匹配零个或一个a
  7. []:字符集,匹配方括号中的任意一个字符。
    • [a-z]:匹配a到z的小写字母
    • [0-9]:匹配0到9的数字
    • [ABCDE]:匹配ABCDE中五个字符的一个
  8. [^]:否定字符集,匹配不在方括号中的任意字符。
  9. {}:用于指定前一个字符或字符集的重复次数
    • {n}:匹配前一个字符恰好出现 n 次。
    • {n,}:匹配前一个字符至少出现 n 次。
    • {n,m}:匹配前一个字符至少出现 n 次,但不超过 m 次。
  10. | 用于表示 “或” 的关系,它可以用来指定匹配多个可选的模式。
    • python|java: 匹配python或者java
  11. ():通常被用来创建捕获组。捕获组允许您将正则表达式中的一部分进行分组,并且在匹配成功后,您可以提取或引用这些分组匹配的内容。
    • 创建捕获组:您可以使用括号将一个或多个正则表达式元素分组在一起,从而形成一个捕获组。这样做可以使您能够对捕获组中的内容进行后续处理或引用。
      例如,(foo) 创建了一个捕获组,用于匹配 “foo”。
    • 提取捕获组内容:在匹配成功后,您可以引用捕获组中匹配的内容。通常,捕获组的内容可以在后续操作中被访问和使用。
      例如,如果使用正则表达式 (foo)\d+ 匹配字符串 “foo123”,那么捕获组 (foo) 中的内容将是 “foo”。
    • 分组重复操作符:括号还可以用来创建分组,以便在后续的正则表达式中重复它们。
      例如,(abc)+ 表示匹配一个或多个 “abc” 的序列。
  12. \:转义字符,用于转义特殊字符。
    • \*: 意味着 * 失去特殊作用,转为待匹配的普通字符
    • \.: 意味着 . 失去特殊作用,转为待匹配的普通字符
  13. \b:匹配单词边界。
  14. \d:匹配数字字符,相当于 [0-9]
  15. \D:匹配非数字字符,相当于 [^0-9]
  16. \s:匹配空白字符,包括空格、制表符、换行符等。
  17. \S:匹配非空白字符。
  18. \w:匹配单词字符,包括字母、数字、下划线。
  19. \W:匹配非单词字符。

常用正则表达式搭配

  • 校验数字的表达式

    • 数字:^[0-9]*$
    • n位的数字:^\d{n}$
    • 至少n位的数字**:^\d{n,}$**
    • m-n位的数字:^\d{m,n}$
    • 零和非零开头的数字:^(0|[1-9][0-9]*)$
    • 非零开头的最多带两位小数的数字:^([1-9][0-9]*)+(.[0-9]{1,2})?$
    • 带1-2位小数的正数或负数:^(-)?\d+(.\d{1,2})$
    • 正数、负数、和小数:^(-|+)?\d+(.\d+)?$
    • 有两位小数的正实数:^[0-9]+(.[0-9]{2})?$
    • 有1~3位小数的正实数:^[0-9]+(.[0-9]{1,3})?$
    • 非零的正整数:^[1-9]\d*$ 或 ^([1-9][0-9]){1,3}$ 或 ^+?[1-9][0-9]$
    • 非零的负整数:^-[1-9][]0-9"$ 或 ^-[1-9]\d$
    • 非负整数:^\d+$ 或 ^[1-9]\d*|0$
    • 非正整数:^-[1-9]\d*|0$ 或 ^((-\d+)|(0+))$
    • 非负浮点数:^\d+(.\d+)?$ 或 ^[1-9]\d*.\d*|0.\d*[1-9]\d*|0?.0+|0$
    • 非正浮点数:^((-\d+(.\d+)?)|(0+(.0+)?))$ 或 ^(-([1-9]\d*.\d*|0.\d*[1-9]\d*))|0?.0+|0$
    • 正浮点数:^[1-9]\d*.\d*|0.\d*[1-9]\d*$ 或 ^(([0-9]+.[0-9][1-9][0-9])|([0-9][1-9][0-9].[0-9]+)|([0-9][1-9][0-9]))$
    • 负浮点数:^-([1-9]\d*.\d*|0.\d*[1-9]\d*)$ 或 ^(-(([0-9]+.[0-9][1-9][0-9])|([0-9][1-9][0-9].[0-9]+)|([0-9][1-9][0-9])))$
    • 浮点数:^(-?\d+)(.\d+)?$ 或 ^-?([1-9]\d*.\d*|0.\d*[1-9]\d*|0?.0+|0)$
  • 校验字符的表达式

    • 汉字:^[\u4e00-\u9fa5]{0,}$
    • 英文和数字:^[A-Za-z0-9]+$ 或 ^[A-Za-z0-9]{4,40}$
    • 长度为3-20的所有字符:^.{3,20}$
    • 由26个英文字母组成的字符串:^[A-Za-z]+$
    • 由26个大写英文字母组成的字符串:^[A-Z]+$
    • 由26个小写英文字母组成的字符串:^[a-z]+$
    • 由数字和26个英文字母组成的字符串:^[A-Za-z0-9]+$
    • 由数字、26个英文字母或者下划线组成的字符串:^\w+$ 或 ^\w{3,20}$
    • 中文、英文、数字包括下划线:^[\u4E00-\u9FA5A-Za-z0-9_]+$
  • 特殊需求表达式

    • Email地址:^\w+([-+.]\w+)@\w+([-.]\w+).\w+([-.]\w+)*$
    • 域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+.?
    • InternetURL:[a-zA-z]+://[^\s]* 或 ^http://([\w-]+.)+[\w-]+(/[\w-./?%&=]*)?$
    • 手机号码:^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$
    • 电话号码(“XXX-XXXXXXX”、“XXXX-XXXXXXXX”、“XXX-XXXXXXX”、“XXX-XXXXXXXX”、"XXXXXXX"和"XXXXXXXX):^((\d{3,4}-)|\d{3.4}-)?\d{7,8}$
    • 国内电话号码(0511-4405222、021-87888822):\d{3}-\d{8}|\d{4}-\d{7}
    • 电话号码正则表达式(支持手机号码,3-4位区号,7-8位直播号码,1-4位分机号): ((\d{11})|^((\d{7,8})|(\d{4}|\d{3})-(\d{7,8})|(\d{4}|\d{3})-(\d{7,8})-(\d{4}|\d{3}|\d{2}|\d{1})|(\d{7,8})-(\d{4}|\d{3}|\d{2}|\d{1}))$)
    • 身份证号(15位、18位数字),最后一位是校验位,可能为数字或字符X:(^\d{15}KaTeX parse error: Undefined control sequence: \d at position 5: )|(^\̲d̲{18})|(^\d{17}(\d|X|x)$)
    • 帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
    • 密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线):^[a-zA-Z]\w{5,17}$
    • 强密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度在 8-10 之间):^(?=.\d)(?=.[a-z])(?=.*[A-Z])[a-zA-Z0-9]{8,10}$
    • 强密码(必须包含大小写字母和数字的组合,可以使用特殊字符,长度在8-10之间):^(?=.\d)(?=.[a-z])(?=.*[A-Z]).{8,10}$
    • 日期格式:^\d{4}-\d{1,2}-\d{1,2}
    • 一年的12个月(01~09和1~12):^(0?[1-9]|1[0-2])$
    • 一个月的31天(01~09和1~31):^((0?[1-9])|((1|2)[0-9])|30|31)$
    • 钱的输入格式:
      1. 有四种钱的表示形式我们可以接受:“10000.00” 和 “10,000.00”, 和没有 “分” 的 “10000” 和 “10,000”:^[1-9][0-9]*$
      2. 这表示任意一个不以0开头的数字,但是,这也意味着一个字符"0"不通过,所以我们采用下面的形式:^(0|[1-9][0-9]*)$
      3. 一个0或者一个不以0开头的数字.我们还可以允许开头有一个负号:^(0|-?[1-9][0-9]*)$
      4. 这表示一个0或者一个可能为负的开头不为0的数字.让用户以0开头好了.把负号的也去掉,因为钱总不能是负的吧。下面我们要加的是说明可能的小数部分:^[0-9]+(.[0-9]+)?$
      5. 必须说明的是,小数点后面至少应该有1位数,所以"10."是不通过的,但是 “10” 和 “10.2” 是通过的:^[0-9]+(.[0-9]{2})?$
      6. 这样我们规定小数点后面必须有两位,如果你认为太苛刻了,可以这样:^[0-9]+(.[0-9]{1,2})?$
      7. 这样就允许用户只写一位小数.下面我们该考虑数字中的逗号了,我们可以这样:^[0-9]{1,3}(,[0-9]{3})*(.[0-9]{1,2})?$
      8. 1到3个数字,后面跟着任意个 逗号+3个数字,逗号成为可选,而不是必须:^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(.[0-9]{1,2})?$
      9. 备注:这就是最终结果了,别忘了"+“可以用”*"替代如果你觉得空字符串也可以接受的话(奇怪,为什么?)最后,别忘了在用函数时去掉去掉那个反斜杠,一般的错误都在这里
    • xml文件:^([a-zA-Z]±?)+[a-zA-Z0-9]+\.[x|X][m|M][l|L]$
    • 中文字符的正则表达式:[\u4e00-\u9fa5]
    • 双字节字符:[^\x00-\xff] (包括汉字在内,可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1))
    • 空白行的正则表达式:\n\s*\r (可以用来删除空白行)
    • HTML标记的正则表达式:<(\S*?)[^>]>.?|<.? /> ( 首尾空白字符的正则表达式:^\s|\s*KaTeX parse error: Undefined control sequence: \s at position 4: 或(^\̲s̲*)|(\s*) (可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式)
    • 腾讯QQ号:[1-9][0-9]{4,} (腾讯QQ号从10000开始)
    • 中国邮政编码:[1-9]\d{5}(?!\d) (中国邮政编码为6位数字)
    • IPv4地址:((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})(.((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})){3}

什么是通配符

通配符是一种用于匹配文件名或路径名的特殊字符,通常用于指定一定模式的文件名或路径名,以进行文件搜索、匹配和操作。在操作系统中,通配符通常由shell(命令行解释器)或其他文件操作工具(如lsfind等)解释和处理。

通配符的作用包括:

  1. 文件搜索和匹配:通配符允许用户根据特定的模式快速定位和匹配文件。通过指定通配符模式,用户可以轻松地搜索符合条件的文件名或路径名。
  2. 文件操作:通配符不仅可以用于文件搜索,还可以与命令行工具一起使用进行文件操作。例如,可以使用通配符来复制、移动、删除符合特定模式的文件,以及对文件进行其他操作。
  3. 批量处理:通过使用通配符,用户可以轻松地批量处理一组文件。例如,可以使用通配符将一组文件传递给脚本或命令,然后对它们进行批量处理。
  4. 简化文件名操作:通配符使得对多个文件进行操作变得更加方便和简洁。而不需要逐个指定每个文件名,只需指定匹配的模式即可。

常用通配符

  1. *:匹配任意数量的字符(包括零个字符)。
    • rm -rf *.o:删除当前文件下的所有 .o 文件
  2. ?:匹配任意单个字符。
    • ls file?.txt:列出所有文件名为 fileX.txt(其中 X 可以是任意字符)的文件。
  3. [...]:匹配指定范围内的任意单个字符。
    • ls file[0-9].txt:列出所有文件名为 file0.txt 到 file9.txt 的文件。
    • ls -ld file[a-z].txt:查看所有文件名为 filea.txt 到 filez.txt 的文件的详细信息。
  4. [!...][^...]:匹配除指定范围内的任意单个字符以外的字符。
    • ls file[!0-9].txt:列出所有文件名为 fileX.txt(其中 X 不是数字字符)的文件。
  5. **:用于递归地匹配文件和目录。
    • dir/**/*.txt: 匹配 “dir” 目录及其所有子目录中以 “.txt” 结尾的文件。

使用通配符的注意事项

  1. 通配符的语法: 不同的环境和编程语言可能有不同的通配符语法。在使用通配符之前,务必查阅相关文档,了解正确的语法和用法。
  2. 文件路径中的通配符: 在文件系统中,通配符通常用于匹配文件名。在使用通配符时,确保了解文件路径中的上下文,以免意外匹配到不希望操作的文件。
  3. 转义特殊字符: 一些字符可能具有特殊含义,如在正则表达式中的.等。如果要匹配它们的字面意义,可能需要使用转义字符(例如,在正则表达式中使用\)。
  4. 大小写敏感性: 有些通配符匹配可能受到大小写敏感性的影响。在一些环境中,通配符可能区分大小写,而在其他环境中则可能不区分。确保你的模式与目标数据的大小写一致。
  5. 模糊匹配的风险: 使用通配符时,要注意可能的模糊匹配。例如,**``**通常匹配任意字符,包括空字符。确保你的模式不会导致不希望的匹配。
  6. 验证模式: 在使用通配符之前,可以通过测试和验证来确保模式的正确性。这可以通过编写测试代码、在终端中执行命令或使用相关工具进行验证。
  7. 文档参考: 始终参考相关的文档和资源,特别是关于所用语言、工具或操作系统的文档。这有助于理解通配符的细节和边界条件。
  8. 谨慎使用通配符删除操作: 在执行删除操作时要特别小心,确保你了解通配符将匹配的内容,并且不会意外删除重要文件。
  • 91
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值