如果xargs是map,那么什么是过滤器?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如果xargs是map,那么什么是过滤器?相关的知识,希望对你有一定的参考价值。
我认为xargs
是UNIX shell的map函数。什么是filter
功能?
编辑:看起来我必须更明确一点。
假设我必须提交一个接受单个字符串作为参数的程序,并返回退出代码0或1.该程序将作为它接受的字符串的谓词。
例如,我可能决定将字符串参数解释为文件路径,并将谓词定义为“此文件是否存在”。在这种情况下,程序可以是test -f
,给定一个字符串,如果文件存在则退出0,否则退出1。
我还必须交出一串串。例如,我可能有一个文件~/paths
包含
/etc/apache2/apache2.conf
/foo/bar/baz
/etc/hosts
现在,我想创建一个新文件~/existing_paths
,它只包含我文件系统中存在的那些路径。就我而言,那就是
/etc/apache2/apache2.conf
/etc/hosts
我想通过读取~/paths
文件,通过谓词test -f
过滤这些行,并将输出写入~/existing_paths
来做到这一点。与xargs
类比,这看起来像:
cat ~/paths | xfilter test -f > ~/existing_paths
这是我正在寻找的假设程序xfilter
:
xfilter COMMAND [ARG]...
其中,对于其标准输入的每行L
,将调用COMMAND [ARG]... L
,如果退出代码为0,则打印L
,否则它不会打印任何内容。
要明确,我不是在寻找:
- 一种过滤存在的文件路径列表的方法。这是一个具体的例子。
- 怎么写这样的程序。我能做到。
我正在寻找:
- 一个预先存在的实现,如
xargs
,或 - 明确解释为什么不存在这一点
如果地图是xargs
,过滤器是......仍然是xargs
。
示例:列出当前目录中的文件并过滤掉非可执行文件:
ls | xargs -I{} sh -c "test -x '{}' && echo '{}'"
这可以通过(非生产就绪)功能方便:
xfilter() {
xargs -I{} sh -c "$* '{}' && echo '{}'"
}
ls | xfilter test -x
或者,您可以通过GNU Parallel使用并行过滤器实现:
ls | parallel "test -x '{}' && echo '{}'"
所以,你正在寻找:
reduce( compare( filter( map(.. list()) ) ) )
什么可以改写为
list | map | filter | compare | reduce
bash
的主要力量是流水线,因此不需要有一个特殊的filter
和/或reduce
命令。事实上,几乎所有unix命令都可以在一个(或多个)函数中起作用:
- 名单
- 地图
- 过滤
- 降低
想像:
find mydir -type f -print | xargs grep -H '^[0-9]*$' | cut -d: -f 2 | sort -nr | head -1
^------list+filter------^ ^--------map-----------^ ^--filter--^ ^compare^ ^reduce^
创建测试用例:
mkdir ./testcase
cd ./testcase || exit 1
for i in {1..10}
do
strings -1 < /dev/random | head -1000 > file.$i.txt
done
mkdir emptydir
您将获得一个名为testcase
的目录,并在此目录中有10个文件和一个目录
emptydir file.1.txt file.10.txt file.2.txt file.3.txt file.4.txt file.5.txt file.6.txt file.7.txt file.8.txt file.9.txt
每个文件包含1000行随机字符串,某些行仅包含数字
现在运行命令
find testcase -type f -print | xargs grep -H '^[0-9]*$' | cut -d: -f 2 | sort -nr | head -1
并且您将获得每个文件中最大的数字行,例如:42
。 (当然,这可以更有效地完成,这仅用于演示)
分解:
find testcase -type f -print
将打印每个普通文件,LIST(并仅减少到文件)。输出:
testcase/file.1.txt
testcase/file.10.txt
testcase/file.2.txt
testcase/file.3.txt
testcase/file.4.txt
testcase/file.5.txt
testcase/file.6.txt
testcase/file.7.txt
testcase/file.8.txt
testcase/file.9.txt
作为MAP的xargs grep -H '^[0-9]*$'
将为列表中的每个文件运行grep
命令。 grep通常用作过滤器,例如:command | grep
,但现在(使用xargs)将输入(文件名)更改为(仅包含数字的行)。输出,很多行如:
testcase/file.1.txt:1
testcase/file.1.txt:8
....
testcase/file.9.txt:4
testcase/file.9.txt:5
线条结构:filename colon number
,只想要数字,所以调用一个纯粹的过滤器,从每行cut -d: -f2
中删除文件名。它输出许多行,如:
1
8
...
4
5
现在减少(获得最大数量),sort -nr
按数字和反向顺序(desc)对所有数字进行排序,因此其输出如下:
42
18
9
9
...
0
0
并且head -1
打印第一行(最大数字)。
当然,您可以使用bash
编程构造(循环,条件等)直接编写自己的list / filter / map / reduce函数,或者您可以使用任何完整的脚本语言,如perl
,awk
,sed
“language”等特殊语言,或dc
(rpn)等。
有一个特殊的过滤命令,如:
list | filter_command cut -d: -f 2
很简单不需要,因为你可以直接使用
list | cut
你可以让awk
做filter
和reduce
功能。
过滤:
awk 'NR % 2 { $0 = $0 " [EVEN]" } 1'
降低:
awk '{ p = p + $0 } END { print p }'
我完全理解你的问题是一个长期的功能程序员,这里是答案:Bash / unix命令流水线并不像你希望的那样干净。
在上面的例子中:
find mydir -type f -print | xargs grep -H '^[0-9]*$' | cut -d: -f 2 | sort -nr | head -1
^------list+filter------^ ^--------map-----------^ ^--filter--^ ^compare^ ^reduce^
一个更纯粹的形式看起来像:
find mydir | xargs -L 1 bash -c 'test -f $1 && echo $1' _ | grep -H '^[0-9]*$' | cut -d: -f 2 | sort -nr | head -1
^---list--^^-------filter---------------------------------^^------map----------^^--map-------^ ^reduce^
但是,例如,grep也有一个过滤功能:grep -q mypattern
,如果匹配模式,它只返回0。
为了获得更像你想要的东西,你只需要定义一个过滤器bash函数并确保导出它以便它与xargs兼容
但后来你遇到了一些问题。比如,test有二元和一元运算符。您的过滤器功能将如何处理?手,你会决定在这些情况下输出什么?不是不可克服的,但很奇怪。假设只有一元操作:
filter(){
while read -r LINE || [[ -n "${LINE}" ]]; do
eval "[[ ${LINE} $1 ]]" 2> /dev/null && echo "$LINE"
done
}
所以你可以做点什么
seq 1 10 | filter "> 4"
5
6
7
8
9
正如我写的那样,我有点喜欢它
以上是关于如果xargs是map,那么什么是过滤器?的主要内容,如果未能解决你的问题,请参考以下文章