Linux Shell管道调用用户定义函数(使shell支持map函数式特性)
Linux中有一个管道的概念,常用来流式的处理文本内容,比如一个文件对其中的每一行应用好几个操作,出于两个方面的考虑可能需要在管道中使用用户定义函数:
1. 刚需: 内置的sed/awk之类的可能没法满足我们的需求,只能使用用户定义函数
2. 代码质量: 如果是流式操作很多很长,那么可能就需要将其进行拆分,将相关的部分封装为一个函数,然后流式调用函数,这样程序的可读性更好,也更容易维护
在管道中上一个程序的标准输出会被放到下一个程序的标准输入,处在管道中的程序需要做的就是读取标准输入中的东西进行处理。
下面是一个在管道中使用用户定义函数的例子,print函数不断地从标准输入流中读取数据然后放到标准输出流中:
#! /bin/bash print(){
while read line
do
echo "$line"
done
} cat original.data | print
上面的例子是比较简单的,那么现在需求又改了,假设读入的每行都是一个数字,需要对数字加1并保存到一个新的文件,那么对上面的脚本进行扩充:
#! /bin/bash add(){
while read line
do
echo $(($line+1))
done
} save(){
while read line
do
echo $line >> result.data
done
} print(){
while read line
do
echo "$line"
done
} # cat original.data | print
cat original.data | add | save
上面的脚本虽然功能实现了,但是有冗余代码,在函数add和save中重复了循环读取输入流数据的代码,现在重构一下,将重复读取的部分抽象出来为一个新的函数map,此函数接受一个可以处理单行的函数的名字function_name,map函数每读取一行就调用function_name函数,将读取到的内容作为参数传入,如果处理单行的函数function_name还有输出,则还可以作为下一个管道命令的输入,这个处理模型类似于函数式编程中的map的概念,即这里通过一个小技巧使得shell支持部分函数式的功能。
现在按照上面的思想来对脚本进行改造:
#! /bin/bash add(){
echo $(($1+1))
} save(){
echo $1 >> result.data
} print(){
echo "$1"
} map(){
function_name=$1
while read line
do
$function_name "$line"
done
} # cat original.data | print
cat original.data | map "add" | map "save"
现在看起来好多了,并且程序的可读性也得到了保障,但是如果我想对add传入一个参数指定究竟要加几怎么办呢,又或者我想在save函数自定义保存到位置又该怎么办呢?
这个很简单,在map中取完第一个参数之后就没再用了,直接shift参数然后直接传递即可,再重构一下代码:
#! /bin/bash add(){
echo $(($1+$2))
} save(){
echo $1 >> $2
} print(){
echo "$1"
} map(){
function_name=$1
shift
while read line
do
$function_name "$line" $@
done
} # cat original.data | print
cat original.data | map "add" 2 | map "save" "result.data"
看起来似乎很完美了,但还能做得更好吗?
如果map方法需要在其它地方调用怎么办?一种方法是将map抽取为utils.sh或者functional.sh之类的库,然后在使用的时候引入它即可,比如新建functional.sh的文件:
##################################################
#
#
# shell 函数式库
#
#
################################################## # $1 函数名
# $[2,] 传递给$1函数的参数
map(){
function_name=$1
shift
while read line
do
$function_name "$line" $@
done
}
使用的时候source functional.sh即可使用map函数。
或者更细粒度的,直接将map抽取为一个文件(以后如果有其它的类似函数也都会抽取为单独的文件),并且放到PATH中,这样使用的时候无需引入,直接就可以使用,比如创建一个文件叫做map:
##################################################
#
#
# functional.map
#
#
################################################## # $1 函数名
# $[2,] 传递给$1函数的参数
map(){
function_name=$1
shift
while read line
do
$function_name "$line" $@
done
} map #@
但是这种方式有个陷阱就是一定要记得每次使用时保证map在$PATH中。
上面就是一步一步优化封装了一个小小的map函数使得shell支持map特性,虽然shell是一门面向字符串的语言,但是稍微对其封装就可以使其具备一些高级语言的特性,提高开发效率,使得程序可读性更好。
.
Linux Shell管道调用用户定义函数(使shell支持map函数式特性)的更多相关文章
- 应用C#和SQLCLR编写SQL Server用户定义函数
摘要: 文档阐述使用C#和SQLCLR为SQL Server编写用户定义函数,并演示用户定义函数在T-SQL中的应用.文档中实现的 Base64 编码解码函数和正则表达式函数属于标量值函数,字符串分割 ...
- 【翻译】Flink Table Api & SQL — 用户定义函数
本文翻译自官网:User-defined Functions https://ci.apache.org/projects/flink/flink-docs-release-1.9/dev/tabl ...
- SQL——用户定义函数
根据用户定义函数返回值的类型,可将用户定义函数分为如下三个类别: (1) 返回值为可更新表的函数 若用户定义函数包含单个 SELECT 语句且该语句可更新,则该函数返回的表也可更新,这样的函数称为内嵌 ...
- SQL 中用户定义函数的使用方法
--用户定义函数的分类: /* 1.标量函数 2.表值函数 2.1内联表值函数 返回单个SELECT语句, 它没有相关的返回变量和函数体 2.2多语句表值函数 是视图和存储过程的结合 可嵌套 */ ...
- SqlServer——用户定义函数
根据用户定义函数返回值的类型,可将用户定义函数分为如下三个类别: (1) 返回值为可更新表的函数 若用户定义函数包含单个 SELECT 语句且该语句可更新,则该函数返回的表也可更新,这样的函数称为内嵌 ...
- SQL Server 2019 中标量用户定义函数性能的改进
在SQL Server中,我们通常使用用户定义的函数来编写SQL查询.UDF接受参数并将结果作为输出返回.我们可以在编程代码中使用这些UDF,并且可以快速编写查询.我们可以独立于任何其他编程代码来修改 ...
- 调试SQL Server的存储过程及用户定义函数
分类: 数据库管理 2005-06-03 13:57 9837人阅读 评论(5) 收藏 举报 sql server存储vb.net服务器sql语言 1.在查询分析器中调试 查询分析器中调试的步骤如下: ...
- Hadoop Hive概念学习系列之hive里的用户定义函数UDF(十七)
Hive可以通过实现用户定义函数(User-Defined Functions,UDF)进行扩展(事实上,大多数Hive功能都是通过扩展UDF实现的).想要开发UDF程序,需要继承org.apache ...
- linux shell 管道命令(pipe)使用及与shell重定向区别
管道命令操作符是:”|”,它仅能处理经由前面一个指令传出的正确输出信息,也就是 standard output 的信息,对于 stdandarderror 信息没有直接处理能力.然后,传递给下一个命令 ...
随机推荐
- Js 中的原始值和引用值
最近遇写 node.js 时到一个问题,把对象当赋值给数组成员时总是出错,比如下面的代码, var Arr = new Array(); var Obj = new Object(); for(var ...
- 如何杀掉Monkey测试
1.adb shell 2.ps | grep monkey 3.kill pid 然后可以看到手机进程中的monkey进程被杀死了,再执行ps | grep monkey,就会发现没有monkey进 ...
- php三种方法从控制结构或脚本中跳出
PHP中,如果希望停止一段代码,根据需要达到的效果不同,可以有三种方法实现: 1. break: 如果在循环中使用了break语句,脚本就会从循环体后面的第一条语句开始执行: 2. continue: ...
- UVAlive4287_Proving Equivalences
题意是告诉你有n个命题,m条递推关系,表示某个命题可以推出另外一个命题. 现在问你至少在增加多少个递推关系可以保证所有命题两两互推. 命题为点,关系为有向边,题目转化成为至少增加多少条有向边使得整个图 ...
- P4910 帕秋莉的手环
题目背景 帕秋莉是蕾米莉亚很早结识的朋友,现在住在红魔馆地下的大图书馆里.不仅擅长许多魔法,还每天都会开发出新的魔法.只是身体比较弱,因为哮喘,会在咏唱符卡时遇到麻烦. 她所用的属性魔法,主要是生命和 ...
- Java之Stream流
Stream流的初步学习 初次学习Stream流的学习笔记,学习之前先了解一下函数式接口 概述 API是一个程序向使用者提供的一些方法,通过这些方法就能实现某些功能.所以对于流API来 说,重点是怎么 ...
- Using Immutable in React + React-Redux
React-Redux Introduction React-Redux is a library for React based on Redux package. And the core ide ...
- 解题:洛谷4178 Tree
题面 重(新)学点分治中...... 普通的点分治一般这几步: 1.找重心 2.从重心开始DFS,得到信息 3.统计经过重心的路径 4.分别分治几棵子树,继续这个过程 然后是常见的(制杖的我的)一些疑 ...
- LGP5075【JSOI2012】分零食
. 题解: 令$F$为欢乐度$f(x) = Ox^2 + Sx + U$的生成函数,常数项为$0$: 令$G(x) = \sum_{i=0}^{A} F^i (x) $ $ans = [x^M]G;$ ...
- CentOS-5的yum源无法使用问题
CentOS-5的yum源无法使用问题 [root@37wan ~]# yum -y install gcc Loaded plugins: fastestmirror Determining fas ...