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}が含まれていないためです。(

試してみたいことの 1 つは、特殊文字をエスケープして、シェルが特殊文字を解釈しようとしないようにすることです。

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

正しくエスケープされた文字列を取得するには多少の労力がかかる場合がありますが、エラー出力を見て何が生成されたかを確認できます。()これらはシェルのサブシェル作成コマンドである$ため、変数の展開を防ぐため、および<入力のリダイレクトを防ぐために をエスケープする必要がありました。


また、必要に応じて、シェルの特殊文字を回避できる方法でフィルタリングする他の方法がある場合があることにも注意してください。あなたのニーズが何であるかを指定していただければ、さらにお手伝いできる可能性があります。

たとえばpax.sh、実際のawk作業を行うシェル スクリプト (例: ) を作成できます。

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

次に、特別なシェル文字を使用せずにマッパーでそのシェル スクリプトを使用します。

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 に答える