Bash特性
Bash(Bourne-Again Shell)是 Linux 和 macOS 等系统中默认的命令行解释器(Shell),其不仅是用户与操作系统交互的接口,还是一种强大的脚本语言。在解释脚本的时候,其会对某些特殊符号(如*
,~
,{}
,$
等)做出对应的处理,而不是单纯看作普通字符。这种特性恰恰展现出了正则表达式的雏形。
命令行展开
* 展开
星号*
可以匹配任意数量的(包括0个)字符,属于路径名展开的一部分,仅匹配实际存在的文件或目录。
1
2
3
4
5
|
# 列出当前目录所有以.txt结尾的文件
ls *.txt
# 列出所有隐藏文件,匹配文件的第一个字符是“.”,第二个字符不是“.”且至少包含一个字符。
ls -d .[!.]?*
|
~ 展开
波浪线~
用来指向主目录,也是路径名展开的一部分。
1
2
3
4
5
|
# 进入到当前用户的主目录
cd ~
# 进入某个用户的主目录
cd ~username
|
{ } 展开
花括号{}
主要用于生成重复模式或序列,常用于快速创建文件/目录、批量操作等场景。其可承载一个以逗号分隔的列表,并将其展开为多个路径。其基本语法为:
1
2
3
|
{元素1,元素2,元素3} # 生成多个字符串
{起始..结束} # 生成数字或字母序列
{起始..结束..步长} # 带步长的序列
|
一些常见的例子如下:
1
2
3
4
|
echo hello_{A,B,C} # 输出hello_A hello_B hello_C
echo {1..100} # 输出1-100
echo {1..100..2} # 输出100内的所有奇数
echo {A,B}{1,2} # 输出 A1 A2 B1 B2,即两个大括号的笛卡尔积
|
$ 符号
$
主要用于引用变量、执行命令替换或算术运算。
变量引用
使用$
+变量名可以对变量进行引用。变量名默认是“贪心匹配”,必要时用 ${}
明确边界。
1
2
3
4
5
|
echo hello_$USER
echo hello_${USER}! # 需要用{}明确变量边界
wd=PATH/TO/WORKING/DIRECTORY
cd $wd
|
此外,还有一些特殊的变量:
$0
:脚本名称
$1
, $2
…:脚本的第1、2个参数
$#
:参数个数
$?
:上一条命令的退出状态(0 表示成功)
$$
:当前进程的 PID
命令替换
用 $()
或反引号执行命令并替换结果:
1
2
3
4
|
echo Today is $(date)
echo Today is `date`
echo $(ls) > log.txt
|
算数计算
用 $(( ))
可以执行数学运算:
1
2
|
echo $((3 + 5 * 2)) # 输出 13
sum=$((10 - 4)) # 将计算结果赋值给变量 sum
|
正则表达式
正则表达式RegExp
是一种用于匹配和操作文本的强大工具,它是由一系列字符和特殊字符组成的模式,用于描述要匹配的文本模式。其中部分字符并不代表其字面含义。正则表达式一般不能被普通的命令识别,而是常与grep
、sed
、awk
等命令连用。此外,正则表达式默认是贪婪匹配,会按顺序匹配符合要求的最长字符串(即使其中的子字符串也符合匹配模式),并且不会进行重叠匹配(即一旦匹配成功则不会再匹配这一部分)。
正则表达式可分为基本正则表达式和扩展正则表达式,其中基本正则表达式对应的元字符包括:^$.[]*
,而扩展正则表达式对应的元字符包括:(){}?+|
基本正则表达式
符号 |
含义 |
^ |
用于模式的左侧,代表以该模式开头的行:^He 匹配以He开头的行。 |
$ |
用于模式的右侧,匹配以该模式结束的行:school$ 匹配以school结尾的行。实际上每行都是以$结尾的 |
^$ |
前两种的组合,以空开头,以空结尾,用来匹配空行。 |
. |
匹配任意一个字符,不能为空字符,也不会匹配空行。 |
\ |
转义字符,使特殊字符恢复其字面含义:\. 指匹配小数点。 |
* |
匹配* 的前一个字符连续出现0次或一次以上:runo*b 可以匹配runb、runob、runoob…… |
.* |
匹配所有内容,即任意字符出现0次或多次。 |
^.* |
匹配以任意内容开头的内容。 |
.*$ |
匹配以任意内容结尾的内容。 |
[abc] |
匹配中括号内任意一个字符。[abc]也可以写作[a-c]。 |
[^abc] |
匹配除了中括号内的字符,中括号里的^指 “取反”。 |
扩展正则表达式
扩展正则表达式支持更多的高级功能,但是需要搭配grep -E
参数才能使用。如果使用普通的grep命令,则在这些特殊字符之前需要加上转义符号\
。
符号 |
含义 |
+ |
匹配+ 的前一个字符连续出现1次或多次:runo+b 可以匹配runob、runoob、runooob…… |
[abc]+ |
匹配中括号内的任意字符出现1次或多次。 |
? |
匹配? 的前一个字符连续出现0次或1次。 |
| |
表示逻辑“或者”:可以把多个正则表达式用` |
( ) |
表示分组过滤,括号内的部分看作一个整体。此外,括号后面还可以被\n 来引用,其中n的数值代表引用第几个括号。 |
a{n,m} |
匹配前一个字符最少n次,最多m次。 |
a{n,} |
匹配前一个字符最少n次。 |
a{n} |
匹配前一个字符恰好n次。 |
a{,m} |
匹配前一个字符最多m次。 |
grep命令
grep
是一个强大的文本搜索工具,它的名字来源于 Global Regular Expression Print(全局正则表达式打印)。它的主要功能是根据指定的模式(如字符串或正则表达式)在文件中搜索匹配的行,并将结果输出到终端或文件。
grep的基本语法
1
|
grep [options] "pattern" file
|
-i
:忽略字符大小写
-o
:仅显示匹配到的字符串本身
-v
:显示未匹配的行
-E
:支持使用扩展正则表达式中的元字符
-q
:静默模式,不输出任何消息
-c
:显示匹配到的行的数目
grep的代表性示例
假设有如下的test.txt文件:
1
2
3
4
|
I like my lover.
I love my lover.
He likes his lovers.
He loves his lovers.
|
以下是两种匹配方法:
1
2
3
4
5
|
# 可以匹配到全部四行
cat test.txt | grep -E "(l..k).*(l..k)"
# 只能匹配到第二行和第四行,这是因为虽然l..k可以匹配到like和love,但是对于后面的引用来说,前面匹配了like,后面也必须是like。
cat test.txt | grep -E "(l..k).*\1"
|
Sed命令
sed
(Stream Editor)是一个强大的文本处理工具,主要用于对文本进行替换、删除、插入、查找等操作。它通过逐行读取输入并根据规则进行处理,非常适合在命令行中快速编辑文件或处理数据流。其核心思想是通过 模式空间(Pattern Space) 和 保持空间(Hold Space) 对文本进行操作,适合快速处理文本的替换、删除、插入等任务。
sed的基本语法
1
|
sed [options] "sed内置命令字符" file
|
-n
:默认取消sed的输出,即不输出不匹配的行
-i
:直接将修改的结果写入文件,否则修改的是内存数据
-e
:设置多次编辑(多个匹配规则)
-r
:支持扩展正则表达式
sed内置命令字符
sed内置命令字符用于对文件进行不同的操作功能,可对文件进行增删改查。包括:
sed内置命令字符 |
作用 |
a |
append,对文本进行追加,即在指定行后面增加一行或多行文本 |
d |
delete,删除匹配行 |
i |
insert,在匹配到的行前插入一行或多行文本 |
p |
print,打印匹配行的内容,常和-n 参数连用 |
s/正则/替换内容/g |
匹配正则内容,然后替换成指定内容,g代表全局匹配 |
sed匹配范围:
范围 |
解释 |
空地址 |
全文处理 |
单地址 |
指定文件某一行 |
/pattern/ |
被模式匹配到的每一行 |
范围区间 |
10,20 十到二十行;10,+5 第十行向下5行;/pattern1/,/pattern2/ |
步长(起始~步长) |
1~2 匹配所有奇数行;2~2 匹配所有偶数行 |
sed的代表性示例
假设有test.fq测序文件,其中一条记录如下:
1
2
3
4
|
@A00183:354:HHF7VDSXX:4:1101:9281:36761
GCCTGGCCTAGGGCTCCGATTCAATCCGTGGTTCGATCGTTCTTGGGTTCTCACGGAGAGGCTGTGATTAAATGGGGCAGGCACGCGCGCGACCGTTGAAATACCGAGCGTTAACTGCGGGGAATCGCGCGCCCGTCCCAATTAATAACA
+
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,FFFFFFFF,FFFFFFFFFFFFFFFFFFFFF:FFF,FFFFF:,F,F:,FF::::F,,,F:,,:F,,:,:,,FFF,:F,F,F:,,,F,F:,F,:,FFF:F,:F,,,:FFF,::FF,,,,F
|
对其应用sed
命令:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
# 打印每条记录的序列(即打印每条记录的第二行)
sed -n "2~4p" test.fq
# 打印含有六个及以上连续的G的行。这里需要加上参数r来使用扩展正则表达式
sed -nr "/G{6,}/p" test.fq
# 提取所有序列,并删除含有六个及以上连续的G的序列,写入新的文件test2.fq
sed -n "2~4p" test.fq | sed -r "/G{6,}/d" > test2.fq
# 在原文件中删除含有六个及以上连续G的行。使用-i参数(慎用!)或-i.bak参数(创建一个备份)
sed -r -i.bak "/G{6,}/d" test.fq
# 将每条记录的第一行的倒数第二个冒号之后的内容都替换成1
sed -r "1~4s/[0-9]*:[0-9]*$/1/g" test.fq
|
awk命令
awk
是一个功能强大的文本处理工具,主要用于处理和分析结构化文本(如日志、表格数据等)。它通过模式(pattern)和动作(action)来操作数据,支持变量、循环、条件判断等编程特性。
awk的基本语法
1
2
3
4
5
|
awk [options] 'pattern{action}' file
# pattern:定义要处理的行的条件(可选)。如果省略,则处理所有行。
# action:对匹配行执行的操作(可选)。如果省略,则默认打印匹配行,即采取print操作。
# file:输入文件,可以指定多个文件,也可以从标准输入(STDIN)读取。
|
-F
:指定分割字符串
-v
:定义或修改一个awk的内部变量
-f
:从脚本中读取awk命令
awk的常用变量
$0
:当前行的完整内容。
$1
、$2
…$n
:当前行按字段分割后的列(默认字段分隔符是空格或制表符)。
NF
:当前行的字段数(Number of Fields),即总列数,是固定值。
NR
:当前行号(Number of Records,从1开始,不是固定值)。
FNR
:当前文件中的行号(如果处理多个文件时有用)。
FS
:输入字段分隔符(默认是空格或制表符)。
OFS
:输出字段分隔符(默认是空格)。
RS
:输入记录分隔符(默认是换行符)。
ORS
:输出记录分隔符(默认是换行符)。
FILENAME
:当前文件名。
awk的代表性示例
有如下test.txt文件:
1
2
3
4
5
|
A11#A12#A13#A14#A15#A16
A21#A22#A23#A24#A25#A26
A31#A32#A33#A34#A35#A36
A41#A42#A43#A44#A45#A46
A51#A52#A53#A54#A55#A56
|
对其应用awk
命令:
1
2
3
4
5
6
7
8
9
10
11
|
# 以#为分割符号,打印第2列
awk -F '#' '{print $2}' test.txt
# 打印第2-4行,第2-4列。这里在前面指定了匹配的起止点,即从NR==2的行开始,匹配到NR==4的行为止。
awk -F '#' 'NR==2,NR==4{print $2,$3,$4}' test.txt
# 打印第一行、倒数第二行和倒数第一行
awk -F '#' '{print $1,$(NF-1),$NF}' test.txt
# 打印第一行、倒数第二行和倒数第一行,并且之间用@连接(即修改输出字段分隔符)
awk -F '#' -v OFS='@' '{print $1,$(NF-1),$NF}' test.txt
|