这是我的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"
还有其他方法可以实现吗?
答案 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/"