从 Miller DSL 调用外部命令

从 Miller DSL 调用外部命令

假设我有以下 CSV:

$ cat test.csv
id,domain
1,foo.com
2,bar.com

使用mlr put,我可以轻松地将任何函数映射到 CSV 中的字段,只要我可以在 Miller 中定义它DSL。因此,例如,将为每个记录mlr --csv put '$id = $id + 1'将 递增1。id

但是,如果我无法在 Miller DSL 中定义该函数(可能是因为它不是纯函数)怎么办?假设我想将 CSV 中的每个域映射到一个 IP 地址。我想做类似的事情mlr --csv put '$ip = shell("nslookup $domain")。是否有捷径可寻?

目前,我正在将输入字段提取到一个单独的文件中,在单独的 shell 脚本中重写它,然后将结果添加回mlr join.然而,这相当混乱,因为我的 CSV 充满了引号逗号和换行符,我需要自己小心处理,而不是依赖 Miller。

答案1

更新: 截至 2019 年 9 月, 这system()DSL功能可以用于此目的。

从 Miller DSL 调用外部命令

Miller DSL 参考文献中有关调用外部命令的部分重定向输出语句:

打印,倾倒,球座,发射量,发射, 和发射关键字都允许您将输出重定向到一个或多个文件或管道命令

我在文档中找不到这一点(除了从示例中推断),但将这些语句与 pipeline-to 命令一起使用的语法似乎是{statement} | {quoted-shell-command}, {unquoted-mlr-expression}.例如:

$ mlr --csv put 'tee | "tr [a-z] [A-Z]", $*' test.csv
id,domain
1,foo.com
2,bar.com
ID,DOMAIN
1,FOO.COM
2,BAR.COM

请注意,管道输出出现在 Miller 的输出之后(在本例中,是未更改的输入,因为tee不会影响流并put发出它)。通过put使用 抑制 的输出,并使用而不是-q提取单个字段,我们可以获得 IP 地址列表:print $domaintee $*

$ mlr --csv put -q 'print | "xargs dig +short", $domain' test.csv
23.23.86.44
104.27.138.186
104.27.139.186

米勒在这里并没有为我们做太多事情。我们仍然必须使用xargs将标准输入转换为参数(因为dig不接受标准输入上的域)。此外,dig的输出包含换行符,这意味着输出不再与输入一对一匹配。由于遵循 Unix 哲学,如果这就是我所需要的,mlr那么将管道连接到末尾会更容易。mlr --headerless-csv-output cut -f domain

将外部命令的输出连接到您的输入

我真正想做的是将调用外部命令的结果分配给 Miller DSL 中的流内变量,据我所知,这是不可能的。然而,通过xargs交换GNUparallel,我们可以使用该--tag选项来跟踪我们给出的参数dig,并从灵活的并发 I/O 中受益:

$ mlr --csv --headerless-csv-output cut -f domain test.csv | parallel --tag dig +short
foo.com 23.23.86.44
bar.com 104.27.139.186
bar.com 104.27.138.186

由于我们正在处理 CSV,因此parallel实际上可以自行处理此问题,尽管我们需要按位置 ( {2}) 而不是名称 ( domain) 访问字段:

$ < test.csv parallel -C "," --skip-first-line --tagstring {2} dig +short {2}
foo.com 23.23.86.44
bar.com 104.27.139.186
bar.com 104.27.138.186

这是一个制表符分隔的对列表(domain, ip),因此我们可以使用 .txt 将其转换回带有标题的 CSV mlr --t2c --implicit-csv-header label domain,ip。然后,由于我们的输出和原始数据test.csv都有一个domain字段,因此我们可以使用它mlr join来生成单个输出表,并mlr nest内爆 的多个值bar.com

$ mlr --csv cut -f domain test.csv | \
  parallel --skip-first-line --tag dig +short | \
  mlr --t2c --implicit-csv-header label domain,ip | \
  mlr --c2p --barred join -f test.csv -j domain then \
  nest --implode --values --across-records -f ip
+---------+----+-------------------------------+
| domain  | id | ip                            |
+---------+----+-------------------------------+
| foo.com | 1  | 23.23.86.44                   |
| bar.com | 2  | 104.27.138.186;104.27.139.186 |
+---------+----+-------------------------------+

相关内容