Shell 如果xargs是map,那么什么是filter?

Shell 如果xargs是map,那么什么是filter?,shell,map,filter,xargs,Shell,Map,Filter,Xargs,我认为xargs是unixshell的映射函数。什么是过滤器功能 编辑:看起来我必须更明确一点 比方说,我需要一个程序,它接受一个字符串作为参数,并返回一个0或1的退出代码。该程序将充当它接受的字符串的谓词 例如,我可能决定将字符串参数解释为文件路径,并将谓词定义为“此文件是否存在”。在这种情况下,程序可能是test-f,给定一个字符串,如果文件存在,则以0退出,否则以1退出 我还得手拿一串弦。例如,我可能有一个包含 /etc/apache2/apache2.conf /foo/bar/baz

我认为
xargs
是unixshell的映射函数。什么是
过滤器
功能

编辑:看起来我必须更明确一点

比方说,我需要一个程序,它接受一个字符串作为参数,并返回一个0或1的退出代码。该程序将充当它接受的字符串的谓词

例如,我可能决定将字符串参数解释为文件路径,并将谓词定义为“此文件是否存在”。在这种情况下,程序可能是
test-f
,给定一个字符串,如果文件存在,则以0退出,否则以1退出

我还得手拿一串弦。例如,我可能有一个包含

/etc/apache2/apache2.conf
/foo/bar/baz
/etc/hosts
现在,我想创建一个新文件,
~/existing\u path
,它只包含文件系统中存在的路径。就我而言,那就是

/etc/apache2/apache2.conf
/etc/hosts
我希望通过读取
~/paths
文件,通过谓词
test-f
过滤这些行,并将输出写入
~/existing\u paths
。与
xargs
类似,这看起来像:

cat ~/paths | xfilter test -f > ~/existing_paths
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^
我正在寻找的是一个虚拟的程序
xfilter

xfilter COMMAND [ARG]...
对于其标准输入的每一行
L
,将调用
命令[ARG]。。。L
,如果退出代码为0,则打印
L
,否则不打印任何内容

明确地说,我不是在寻找:

xfilter COMMAND [ARG]...
  • 按存在筛选文件路径列表的一种方法。这是一个具体的例子
  • 如何编写这样一个程序。我能做到
我正在寻找:

  • 预先存在的实现,如
    xargs
    ,或
  • 这是为什么不存在的一个清楚的解释

您可以让
awk
执行
过滤
减少
功能

过滤器:

awk 'NR % 2 { $0 = $0 " [EVEN]" } 1'
减少:

awk '{ p = p + $0 } END { print p }'

因此,您正在寻找:

 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
每个文件包含1000行随机字符串,有些行仅包含数字

现在运行命令

find testcase -type f -print | xargs grep -H '^[0-9]*$' | cut -d: -f 2 | sort -nr | head -1
您将从每个文件中获得最大的数字行,如:
42
。(当然,这可以更有效地完成,这仅用于演示)

分解:

findtestcase-typef-print
将打印每个普通文件,因此,列出(并且仅减少到文件)。输出:

xargs grep-H'^[0-9]*$”
as-MAP将为列表中的每个文件运行
grep
命令。grep通常用作过滤器,例如:
命令| grep
,但现在(使用xargs)将输入(文件名)更改为(仅包含数字的行)。输出,许多行如下:

testcase/file.1.txt:1
testcase/file.1.txt:8
....
testcase/file.9.txt:4
testcase/file.9.txt:5
1
8
...
4
5
行的结构:
filename冒号
,只需要数字,因此调用纯过滤器,从每行
cut-d:-f2中去除文件名。它输出许多行,如:

testcase/file.1.txt:1
testcase/file.1.txt:8
....
testcase/file.9.txt:4
testcase/file.9.txt:5
1
8
...
4
5
现在reduce(获取最大的数字)和
sort-nr
对所有数字进行数字排序和逆序排序(desc),因此其输出如下所示:

42
18
9
9
...
0
0
然后
头-1
打印第一行(最大数字)

当然,您可以直接使用
bash
编程结构(循环、条件等)编写自己的list/filter/map/reduce函数,也可以使用任何成熟的脚本语言,如
perl
、特殊语言,如
awk
sed
“language”或
dc
(rpn)等

具有特殊的过滤命令,例如:

list | filter_command cut -d: -f 2
不需要简单,因为您可以直接使用

list | cut

如果映射为
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 '{}'"

作为一名长期从事函数式编程的程序员,我完全理解您在这里提出的问题,答案是: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^
更纯粹的形式如下所示:

cat ~/paths | xfilter test -f > ~/existing_paths
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-qmypattern
,如果与模式匹配,它只返回0

为了得到更像您想要的东西,您只需定义一个filter bash函数,并确保将其导出,使其与xargs兼容

但是你会遇到一些问题。和此类似,test有二元运算符和一元运算符。你的过滤函数将如何处理这个问题?另一方面,对于这些情况,您决定在true上输出什么?不是不可逾越的,但很奇怪。仅假设一元运算:

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
有一个通用shell命令作为参数,它是映射输入行的函数。类似地,
filter
应该使用shell命令作为输入行上的谓词(例如,基于其返回代码是否为0)。在您的示例中,谓词仅在
awk
-speak中定义。@jameshfisher我猜您需要的是shell。我不确定您的意思,比如?@jameshfisher在
bash
like
中定义一个循环,而IFS=read-r行;做完成
。你可以使用所有你想让它按你想要的方式工作的变量,并且有
$?
if
条件或逻辑运算符
&&
|
来控制逻辑。因为fork N倍于com是无效的