0

这是我的 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" 

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

4

1 回答 1

1

问题不在于if本身,而是与引号已从您的awk命令中删除的事实有关。

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

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

当您尝试直接执行该引号剥离命令时:

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

pax> echo hello | awk {print}
hello

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

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

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

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


另请记住,根据您的需要,可能还有其他过滤方式,可以避免 shell 特殊字符。如果您指定您的需求,我们可能会提供进一步的帮助。

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

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

然后在映射器中使用该 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/"
于 2013-05-22T01:50:06.833 回答