awk在hadoop的映射器中不起作用

时间:2013-05-22 01:45:24

标签: awk hadoop-streaming

这是我的hadoop工作:

hadoop streaming \
-D mapred.map.tasks=1\
-D mapred.reduce.tasks=1\
-mapper "awk '{if(\$0<3)print}'" \  # doesn't work
-reducer "cat" \
-input "/user/***/input/" \
-output "/user/***/out/"

这项工作总是失败,错误地说:

sh: -c: line 0: syntax error near unexpected token `('
sh: -c: line 0: `export TMPDIR='..../work/tmp'; /bin/awk { if ($0 < 3) print } '

但如果我将-mapper更改为: -mapper“awk'{print}'” 它没有任何错误。 if(..)的问题是什么?

更新:

感谢@paxdiablo的详细解答。

我真正想做的是在将输入数据汇总到我的自定义x之前过滤掉第一列大于bin的一些数据。所以-mapper实际上是这样的:

-mapper "awk -v x=$x{if($0<x)print} | ./bin" 

还有其他方法可以实现吗?

1 个答案:

答案 0 :(得分:1)

问题不在于if本身,而在于从awk命令中删除了引号这一事实。

当你查看错误输出时,你会意识到这一点:

sh: -c: line 0: `export TMPDIR='..../work/tmp'; /bin/awk { if ($0 < 3) print } '

当你尝试直接执行quote-stripped命令时:

pax> echo hello | awk {if($0<3)print}
bash: syntax error near unexpected token `('

pax> echo hello | awk {print}
hello

{print}的工作原因是因为它不包含shell特殊的(字符。

您可能想要尝试的一件事是转义特殊字符以确保shell不会尝试解释它们:

{if\(\$0\<3\)print}

获取正确转义的字符串可能需要一些努力,但您可以查看错误输出以查看生成的内容。我不得不逃避(),因为它们是shell子shell创建命令,$是为了防止变量扩展,而<是为了防止输入重定向。


另请注意,根据您的需要,可能还有其他方法可以过滤,这些方法可以避免使用shell特殊字符。如果您指定了您的需求,我们可能会进一步提供帮助。

例如,您可以创建一个shell脚本(例如,pax.sh)来为您执行实际的awk工作:

#!/bin/bash
awk -v x=$1 'if($1<x){print}'

然后在mapper中使用该shell脚本,没有任何特殊的shell字符:

hadoop streaming \
  -D mapred.map.tasks=1 -D mapred.reduce.tasks=1 \
  -mapper "pax.sh 3" -reducer "cat" \
  -input "/user/***/input/" -output "/user/***/out/"