Bash 成为每个类 Unix 或根据 Unix 的操作系统的默许自动化言语。每个系统管理员、DevOps 工程师和程序员一般运用 Bash 来编写具有重复指令序列的 shell 脚本。Bash 脚本一般包括运转其他程序二进制文件的指令。在大多数情况下,咱们或许需求在 shell 脚本中处理数据并创立逻辑流程。因而,咱们经常不得不在咱们的 shell 脚本中添加条件语句和文本操作语句。
传统的 Bash 脚本和曩昔运用旧 Bash 解说器版别的程序员一般运用awk
、sed
、tr
和cut
指令进行文本操作。这些是单独的程序。尽管这些文本处理程序供给了很好的功用,但它们会减慢您的 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 用户已经知道,能够运用grep
andsed
进行根据正则表达式的文本搜索。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_REMATCH
shell 变量中。该变量是一个只读数组,将匹配到的全部数据存放在榜首个索引中。假如你运用子模式,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
上述ver1
和ver2
变量在声明期间接纳一个大小写属性,因而每当您为特定变量赋值时,Bash 都会根据变量属性转化文本大小写。
拆分字符串(字符串到数组的转化)
declare
Bash 答应您运用内置的界说索引和关联数组。大多数通用编程言语都split
在字符串目标中或经过规范库函数(Go 的strings.Split
函数)供给办法。您能够在 Bash 中运用多种办法拆分字符串并创立数组。例如,咱们能够更改IFS
为所需的分隔符并运用read
内置的。或许,咱们能够运用tr
带有循环的指令并结构数组。或许,运用内置参数扩展是另一种办法。Bash 中有许多字符串拆分办法。
运用IFS
andread
是拆分字符串的最简略且无错误的办法之一:
#!/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[@]} " # 包括当前目录内容