Hi,我是Johngo~
Linux、shell,很多初学者可能非常陌生,但是对于算法、数据、大数据相关的同学,这个又是一个不可避免的学习内容~
Shell 编程在机器学习和数据处理领域非常重要,尽管它通常不像 Python 或 R 那样直接用于开发机器学习模型。但是在数据计算流程中的重要性不言而喻。
- 数据预处理与处理: Shell 脚本经常用于执行数据清洗、转换和预处理操作。利用像
awk
、sed
、grep
这样的工具,可以快速地处理大量文本数据,例如日志文件、CSV 文件等,以便于进一步的分析和模型训练。 - 自动化流程: 在机器学习项目中,需要执行大量重复性任务,例如数据下载、数据转换、模型训练和测试等。Shell 脚本可以帮助自动化这些任务,节省大量时间并减少人为错误。
- 集成不同的工具和语言: 机器学习和数据处理项目通常涉及到多种工具和编程语言。Shell 脚本可以作为它们之间的粘合剂,将各个部分整合到一起,例如从数据库导出数据、调用 Python 脚本进行分析,然后使用另一个工具进行可视化。
- 环境管理和部署: Shell 脚本可以用于设置和管理数据科学和机器学习环境,包括安装软件、管理依赖、配置系统变量等。在生产环境中,Shell 脚本通常用于模型的部署和维护。
- 处理大规模数据集: 当处理大规模数据集时,尤其是在分布式系统上,Shell 脚本可以用来控制和协调数据处理任务的执行。例如,它可以用于在 Hadoop 或 Spark 集群上提交和监控作业。
- 快速原型和探索性数据分析: 对于快速的数据探索和原型开发,Shell 提供了一种简单而强大的方式来查看、过滤和汇总数据。
虽然数据科学和机器学习工具和库(例如 Python 中的 Numpy、Pandas 和 Scikit-Learn等等)为数据处理和建模提供了更高级的功能,但 Shell 编程仍然是数据科学家和机器学习工程师工具箱中的一个重要组成部分。它在早期数据的处理以及整个数据处理流程的自动化和系统集成方面非常非常重要。
除了基础的shell编程的知识,比较重要的还有 sed
和 awk
。
今儿咱们来聊聊awk,尽管awk的内容相当的对,一度让人想要放弃。
但是今儿咱们先来聊聊基础的内容~
# 探索 Awk 命令的语法
Awk是一种用于文本处理和数据提取的脚本语言,它基于模式匹配和操作指令的组合。
1. 语法结构
代码语言:javascript复制awk 'pattern { action }' input_file
pattern
:匹配输入数据中的模式。可以是正则表达式或逻辑表达式。action
:在匹配到模式时执行的动作。可以是任何合法的Awk命令。input_file
:待处理的输入文件。
2. 工作原理
对于输入文件的每一行,Awk将逐行读取数据,并匹配模式。当模式与行匹配时,Awk执行相应的动作。动作可以是打印行、修改行、拆分行等。
3. 示例
假设我们有一个名为file.txt
的文本文件,内容如下:
apple,3
orange,2
banana,5
我们想要使用Awk命令提取第一列(水果名称),并打印输出。下面是相应的Awk命令:
代码语言:javascript复制awk -F "," '{print $1}' file.txt
-F ","
:指定字段分隔符为逗号。'{print $1}'
:匹配所有行,并打印第一个字段。
运行以上命令,输出结果为:
代码语言:javascript复制apple
orange
banana
在这个案例中,可以看到,Awk命令通过模式{print 1}匹配所有行,并通过动作print 1打印第一个字段数据。
# 理解 Awk 程序结构 (BEGIN, body, END)
Awk 程序结构由三个部分组成:BEGIN 块、body 块和 END 块。
1. BEGIN 块
该块在 Awk 程序执行之前被执行,用于初始化变量或执行其他一次性的操作。它是可选的,如果没有指定 BEGIN 块,则会跳过该部分。
语法
代码语言:javascript复制BEGIN {
# 执行初始化操作和其他一次性的操作
}
案例
假设我们有一个名为file.txt
的文本文件,内容如下:
apple 3
orange 2
banana 5
体会BEGIN模块如何编写:
代码语言:javascript复制awk 'BEGIN {
print "开始执行 Awk 程序"
sum = 0
}
{
sum = $2
}
END {
print "执行结束"
print "总和为:", sum
}' file.txt
执行结果:
代码语言:javascript复制开始执行 Awk 程序
执行结束
总和为: 10
代码解释:
在该案例中,BEGIN 块用于打印一条开始执行的消息并初始化变量 sum。body 块紧接着执行,在每行的第 2 个字段上将其值添加到 sum 变量中。最后,END 块在程序执行完毕后被执行,打印一条结束执行的消息和 sum 的总和。
2. body 块
这个块是 Awk 程序的主要部分,它在每一行上被执行。可以在 body 块中执行各种操作,如打印、计算、条件判断等等。
语法:
代码语言:javascript复制{
# 在每一行上执行的操作
}
案例:
同样使用file.txt
文本文件,内容如下:
apple 3
orange 2
banana 5
body 块内容:
代码语言:javascript复制awk '{
if ($2 > 3) {
print "大于 3"
}
else {
print "小于等于 3"
}
}' file.txt
执行结果:
代码语言:javascript复制小于等于 3
小于等于 3
大于 3
代码解释
在该案例中,body 块用于判断第 2 个字段的值是否大于 10,并打印相应的结果。
3. END 块
该块在 Awk 程序执行完毕后被执行一次,用于做一些最终的计算、打印总结或清理操作等。
语法:
代码语言:javascript复制END {
# 执行最终操作
}
案例:
代码语言:javascript复制END {
print "执行结束"
print NR "行被处理"
}
代码解释 在该案例中,END 块用于打印一条结束执行的消息和处理的总行数。
通过这三个部分的组合,可以编写复杂的 Awk 程序来处理文本数据。其中,BEGIN 和 END 块是可选的,body 块是必需的,至少要有一个。根据具体需求,可以在这三个部分中包含任意数量的代码块。
# 如何执行 awk 程序
要执行 AWK 脚本,你可以将 AWK 代码保存在一个文本文件中,或者直接在命令行中运行它。
下面是两种执行 AWK 脚本的方法:
方法 1: 使用命令行直接执行
在这种方法中,你直接将 AWK 代码作为命令行的一部分。例如,要运行咱们后面提到的单词计数示例,你可以这样做:
代码语言:javascript复制echo "hello world hello" | awk '{for (i = 1; i <= NF; i ) wordCount[$i] ;} END {for (word in wordCount) print word ": " wordCount[word]}'
这里,echo "hello world hello"
命令产生文本输入,然后通过管道 |
传递给 awk
命令。AWK 脚本在单引号内给出。
方法 2: 使用脚本文件执行
另一种方法是将 AWK 代码保存在一个文件中,然后执行该文件。比如,你可以将 AWK 代码保存到一个名为 wordcount.awk
的文件中:
{
for (i = 1; i <= NF; i ) {
wordCount[$i]
}
}
END {
for (word in wordCount) {
print word ": " wordCount[word]
}
}
然后,你可以使用以下命令来执行这个脚本:
代码语言:javascript复制awk -f wordcount.awk file.txt
这里,input.txt
是包含你想要处理的文本的文件。-f
选项告诉 AWK 从指定的文件中读取脚本。
注意事项
- 确保你的系统上安装了 AWK。大多数 UNIX 和类 UNIX 系统(如 Linux 和 macOS)默认安装了 AWK。
- 如果你的 AWK 脚本包含特殊字符(如
$
),在命令行直接执行时可能需要特别注意引号的使用。 - 当使用文件执行时,确保脚本文件的权限允许你执行它(在需要时可以使用
chmod
命令调整权限)。
# 学习打印命令的应用
学习打印命令在awk编程中是非常重要的,它可以帮助我们输出程序的结果或调试信息。
1. 基础语法
在awk中,打印命令的语法是通过使用print或printf函数来实现的。
代码语言:javascript复制print expression1, expression2, ...
printf format, expression1, expression2, ...
其中expression是要打印的内容,可以是变量、常量或表达式。
format是一个格式控制字符串,用于指定打印的格式。
2. 案例
假设我们有一个包含学生信息的文件,每一行包括学生的姓名、分数和班级,用逗号分隔。
我们想要读取文件并打印出每个学生的姓名和分数。
下面是 file.txt 文件的内容:
代码语言:javascript复制John,85,A
Mary,92,B
Tom,78,C
我们可以使用awk编程来实现这个目标。
代码语言:javascript复制awk 'BEGIN{FS=","} {print $1, $2}' file.txt
在这个代码中,我们使用 BEGIN 模块来设置分隔符为逗号,这样就可以按照逗号分割每一行的内容。在主模块中,我们使用print命令来打印每个学生的姓名和分数,
2表示第二个字段(分数)。
最后,我们指定了要处理的文件file.txt。
运行以上命令后的输出结果将为:
代码语言:javascript复制John 85
Mary 92
Tom 78
在这个例子中,我们通过学习打印命令,成功地读取了文件并输出了我们所需的学生姓名和分数。
# 掌握模式匹配的技巧
模式匹配的技巧 可以帮助我们搜索和处理文本中符合特定模式的数据。
1. 基本语法
使用正则表达式模式匹配
- 使用
~
运算符可以用正则表达式匹配文本。 - 使用
!~
运算符可以用正则表达式排除匹配。
使用字符集匹配
- 使用
[]
来定义一个字符集,可以匹配字符集中的任意一个字符。 - 使用
-
来表示一个字符范围,例如[0-9]
可以匹配任意一个数字字符。
2. 示例
代码语言:javascript复制# 匹配所有以a开头的单词
awk '/^a/ { print $0 }' file.txt
# 匹配包含数字的行
awk '/[0-9]/ { print $0 }' file.txt
# 打印所有不以a结尾的单词
awk '$NF !~ /a$/ { print $0 }' file.txt
在上面的示例中,我们使用正则表达式来匹配文本中的模式。
第一个代码块使用^a
匹配所有以a开头的单词,并打印匹配到的行。
第二个代码块使用[0-9]
匹配包含数字的行,并打印匹配到的行。
最后一个代码块使用NF !~ /a/排除以a结尾的单词,并打印匹配到的行。