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 信息没有直接处理能力.然后,传递给下一个命令 ...
随机推荐
- Python Matplotlib绘图库 安装
一般我们在做科学计算的时候,首先会想到的是matlab,但是呢,一想到matlab安装包那么大,我就有点不想说什么了. Matplotlib 是python最著名的绘图库,它提供了一整套和matlab ...
- Idea使用Mybatis Generator 自动生成代码
(1)创建一个maven工程 (2)配置pom文件 <dependencies> <dependency> <groupId>mysql</groupId&g ...
- MDN & IRC
MDN IRC MDN IRC xgqfrms https://developer.mozilla.org/en-US/docs/Mozilla/QA/Getting_Started_with_IRC ...
- sqlserver中where条件加判断
我想实现如下功能: where case when (@a = null) then 1 = 1 else @a=a and b=@b 但是这样报错,经过翻阅资料找到如下解决方案: where (1 ...
- forEach遍历数组对象且去重
forEach遍历数组对象 var obj1 = [{ key: '01', value: '哈哈' }, { key: '02', value: '旺旺' }, { key: '03', value ...
- line search中的重要定理 - 梯度与方向的点积为零
转载请注明出处:http://www.codelast.com/ 对精确的line search(线搜索),有一个重要的定理: ∇f(xk+αkdk)Tdk=0 这个定理表明,当前点在dk方向上移动到 ...
- 题解 P4379 【[USACO18OPEN]Lemonade Line】
不敢快速排序又想要快排的速度,还不用STL的小伙伴们看这里! 小金羊终于学会了堆排以外的另外的一种排序 (打个题解巩固一下) 归并排序(mergesort): 时间复杂度和快排一样的优秀. 先说归并排 ...
- 【POJ2411】Mondriaan's Dream(轮廓线DP)
[POJ2411]Mondriaan's Dream(轮廓线DP) 题面 Vjudge 题解 这题我会大力状压!!! 时间复杂度大概是\(O(2^{2n}n^2)\),设\(f[i][S]\)表示当前 ...
- 谷歌发布 Android 8.1 首个开发者预览版,优化内存效率
今晨,谷歌推出了 Android 8.1 首个开发者预览版,此次升级涵盖了针对多个功能的提升优化,其中包含对 Android Go (设备运行内存小于等于 1 GB)和加速设备上对机器学习的全新神经网 ...
- Android仿iPhone 滚轮控件 实现
Android_开发 实用滚轮效果选择数字http://blog.csdn.net/zhangtengyuan23/article/details/8653771 Android仿iPhone滚轮控件 ...