Bash 成为每个类 Unix 或根据 Unix 的操作系统的默许自动化言语。每个系统管理员、DevOps 工程师和程序员一般运用 Bash 来编写具有重复指令序列的 shell 脚本。Bash 脚本一般包括运转其他程序二进制文件的指令。在大多数情况下,咱们或许需求在 shell 脚本中处理数据并创立逻辑流程。因而,咱们经常不得不在咱们的 shell 脚本中添加条件语句和文本操作语句。

传统的 Bash 脚本和曩昔运用旧 Bash 解说器版别的程序员一般运用awksedtrcut指令进行文本操作。这些是单独的程序。尽管这些文本处理程序供给了很好的功用,但它们会减慢您的 Bash 脚本,因为每个特定指令都有相当长的进程发动时间。现代 Bash 版别经过众所周知的参数扩展功用供给内置的文本处理功用。

在这个故事中,我将解说一些内置的字符串操作语法,您能够运用这些语法在 Bash 脚本中高效地处理文本。

子串提取和替换

子字符串指的是传染性片段或特定字符串的一部分。在各种脚本场景中,咱们需求从字符串段中提取子串。例如,您或许只需求从包括扩展名的完整文件名中获取文件名段。此外,您或许需求用特定的字符串段替换子字符串(即,更改文件名的文件扩展名)。

经过供给字符方位和长度,子字符串提取非常容易:

#!/bin/bash
 str= "2023-10-12" 
echo  " ${str:5:2} "  # 10 
echo  " ${str::4} "  # 2023 
echo  "2022- ${str:5} ”  #2022-10-12

您甚至能够从右侧进行子串计算,如下所示:

#!/bin/bash
 str= "backup.sql" 
echo  "original ${str:(-4)} "  # original.sql

Bash 还为子字符串替换供给了高效的内置语法:

#!/bin/bash
 str= "obin-linux_x64_bin" 
echo  " ${str/x64/armhf} "  # obin-linux_armhf_bin 
echo  " ${str/bin/dist} "  # odist-linux_x64_bin 
echo  " ${str// bin/dist} "  # odist-linux_x64_dist

当您运用某些字符串(如文件名、路径等)时,您或许有必要替换字符串前缀和后缀。用另一个扩展名替换文件扩展名就是一个很好的比如。看下面的比如:

#!/bin/bash
 str= "db_config_backup.zip" 
echo  " ${str/%.zip/.conf} "  # db_config_backup.conf 
echo  " ${str/#db/settings} "  # settings_config_backup.zip

在上面的子串替换比如中,咱们运用了精确的子串段来进行匹配,可是你也能够运用通配符来运用子串的一部分,*如下所示:

#!/bin/bash
 str= "db_config_backup.zip" 
echo  " ${str/%.*/.bak} "  # db_config_backup.conf 
echo  " ${str/#*_/new} "  # newbackup.zip

假如您不知道要搜索的确切子字符串,上述办法很有用。

正则表达式匹配、提取和替换

许多 Unix 或 GNU/Linux 用户已经知道,能够运用grepandsed进行根据正则表达式的文本搜索。sed帮助咱们进行正则表达式替换。您能够运用内置的 Bash 正则表达式功用来比这些外部二进制文件更快地处理文本。

您能够运用 if 条件和=~运算符执行正则表达式匹配,如以下代码片段所示:

#!/bin/bash
 str= "db_backup_2003.zip"
假如[[ $str =~ 200[0-5]+ ]]; 然后
    echo  "regex_matched" 
fi

假如需求,您还能够用内联条件替换 if 语句:

[[ $str =~ 200[0-5]+ ]] && echo "regex_matched"

一旦 Bash 解说器执行正则表达式匹配,它一般会将一切匹配项存储在BASH_REMATCHshell 变量中。该变量是一个只读数组,将匹配到的全部数据存放在榜首个索引中。假如你运用子模式,Bash 会逐步将这些匹配保留在其他索引中:

#!/bin/bash
 str= "db_backup_2003.zip"
假如[[ $str =~ (200[0-5])(.*)$ ]]; 然后
    echo  " ${BASH_REMATCH[0]} "  # 2003.zip 
    echo  " ${BASH_REMATCH[1]} "  # 2003 
    echo  " ${BASH_REMATCH[2]} "  # .zip 
fi

还记得咱们在之前的子字符串匹配中运用了通配符吗?同样,能够在参数扩展中运用正则表达式界说,如以下示例所示:

#!/bin/bash
 str= "db_backup_2003.zip"
 re= "200[0-3].zip" 
echo  " ${str/$re/new} .bak"  # db_backup_new.bak

子串删去技能

在许多文本处理需求中,咱们经常需求通曩昔除不需求的子串来预处理文本片段。例如,假如您提取带有v前缀和一些内部版别号的版别号并想要找到首要版别号,则有必要删去一些子字符串。您能够运用相同的子字符串替换语法,但省掉字符串删去的替换字符串参数,如下所示:

#!/bin/bash
 str= "ver5.02-2224.e2"
 ver= " ${str#ver} " 
echo  $ver  # 5.02-2224.e2
 maj= " ${ver/.*} " 
echo  $maj  # 5

在上面的示例中,咱们运用了精确的子字符串和通配符来删去子字符串,但您也能够运用正则表达式。检查怎么提取没有过多字符的洁净版别号:

#!/bin/bash
 str= "ver5.02-2224_release"
 ver= " ${str//[a-z_]} " 
echo  $ver  # 5.02-2224

个案转化和根据个案的变量

即使是规范的 C 言语也供给了转化字符大小写的函数。简直一切现代编程言语都供给了大小写转化的内置函数。作为一种指令言语,Bash 不供给大小写转化功用,但它经过参数扩展和变量声明为咱们供给了大小写转化功用。

检查以下转化字母大小写的示例:

#!/bin/bash
 str= "你好 Bash!" 
lower= " ${str,,} "
 upper= " ${str^^} " 
echo  $lower  # 你好 bash!
echo  $upper  # 你好 BASH!

您还能够只将特定字符串的榜首个字符大写或小写,如下所示:

#!/bin/bash
 ver1= "V2.0-release"
 ver2= "v4.0-release" 
echo  " ${ver1,} "  # v2.0-release 
echo  " ${ver2^} "  # V4.0 -发布

假如您需求使特定变量严厉为大写或小写,则无需一直运转大小写转化函数。相反,您能够运用内置指令将事例属性添加到特定变量declare,如以下示例所示:

#!/bin/bash 
declare -l ver1 
declare -u ver2 
ver1= "V4.02.2"
 ver2= "v2.22.1" 
echo  $ver1  # v4.02.2 
echo  $ver2  #V2.22.1

上述ver1ver2变量在声明期间接纳一个大小写属性,因而每当您为特定变量赋值时,Bash 都会根据变量属性转化文本大小写。

拆分字符串(字符串到数组的转化)

declareBash 答应您运用内置的界说索引和关联数组。大多数通用编程言语都split在字符串目标中或经过规范库函数(Go 的strings.Split函数)供给办法。您能够在 Bash 中运用多种办法拆分字符串并创立数组。例如,咱们能够更改IFS为所需的分隔符并运用read内置的。或许,咱们能够运用tr带有循环的指令并结构数组。或许,运用内置参数扩展是另一种办法。Bash 中有许多字符串拆分办法。

运用IFSandread是拆分字符串的最简略且无错误的办法之一:

#!/bin/bash
 str= "C,C++,JavaScript,Python,Bash"
 IFS= ','  read -ra arr <<< " $str " 
echo  " ${#arr[@]} "  # 5 
echo  " ${arr[0]} "  # C 
echo  " ${arr[4]} "  # Bash

上面的代码片段用作,切割分隔符,并运用read内置指令创立一个根据IFS.

即使有最简略的办法来处理没有 的拆分read,也要确保没有躲藏的问题。例如,下面的拆分实现非常简略,可是当您将*(扩展到当前目录的内容)作为元素并以空格作为分隔符时,它会中断:

#!/bin/bash 
# 正告:这段代码有几个躲藏的问题。
str= "C,Bash,*"
 arr=( ${str//,/ } ) 
echo  " ${#arr[@]} "  # 包括当前目录内容