我厌倦了hadoop fs
仅查询 HDFS 的缓慢启动时间。不过,这对于 HDFS 本身来说不是问题,因为在 Pig“grunt shell”中使用 HDFS 文件系统命令非常快。但是,当我只想发出一些 HDFS 命令时,总是启动 grunt shell 是不切实际的。因此,我编写了这个脚本来在后台启动一个 grunt shell 实例,并使其保持打开状态以供后续调用:
#!/bin/bash
in=/tmp/grunt_in
out=/tmp/grunt_out
err=/tmp/grunt_err
if [ ! -p $in ]
then
mkfifo $in
mkfifo $out
( pig <>$in >$out 2>$err; rm $in $out ) &
disown
fi
>$err # Truncate errors
echo "fs $*" >$in
echo >$in
echo "-- end" >$in
sed -n '/^grunt> -- end/q;/^grunt>/d;p' $out
cat $err >&2
当然,不仅输入必须发送到脚本,而且脚本的输出也必须重定向到我当前的 bash 会话。我在这里使用/tmp/grunt_in
和/tmp/grunt_out
FIFO 来实现这一点。为了弄清楚何时pig
处理命令,我发送一条"-- end"
注释并在sed
正在监听输出的命令中检测到该注释,以使其在遇到end
令牌时退出,并通过跳过所有提示仅输出相关部分grunt>
。
<>$in
请注意,即使我将输出重定向到,我也必须附加输入 FIFO以$out
防止 Pig 在第一个命令后退出。我不知道到底为什么,但我认为它是这样工作的。
这实际上已经很好用了。例如
$ time hadoop fs -ls
Found 38 items
[ skipped output ]
real 0m1.828s
user 0m3.160s
sys 0m0.137s
$ time dfs -ls
[apollo@dc1-had03-clusterutil01 reporting-APO-5394]$ time dfs -ls
Found 38 items
[ skipped output ]
real 0m0.149s
user 0m0.003s
sys 0m0.006s
(我在这里调用了我的脚本dfs
。)目前只剩下两个我无法解决的问题:
- 当我第一次调用该脚本时(即 fifo
/tmp/grunt_in
尚不存在且 pig 实例在后台启动时),我的终端设置不知何故被搞乱了。我再也得不到输入的回显,所以我必须盲目地输入reset
才能恢复正常的终端。但后续调用工作正常。 当我尝试在 HDFS 上输出文件内容时,
-cat
或者-text
输出被任意截断。例如:$ hadoop fs -text some-medium-size.gz|wc -l 3606 $ dfs -text some-medium-size.gz|wc -l text: Unable to write to output stream. 9
请注意此处的错误消息
text: Unable to write to output stream.
,它不是来自,pig
而是来自fs -text
命令 fromhadoop
。有时它会在前 9 或 10 行被截断,就像这里一样,有时会在中间的某个地方被截断。这很奇怪。我还尝试手动将命令发送到/tmp/grunt_in
并读取/tmp/grunt_out
withcat
,得到相同的结果,但这证实了我的解析 withsed
不是这里的问题。一般来说,对于大输出来说,这似乎也不是问题,例如,对于长目录列表,它工作得很好:$ dfs -ls -R|wc -l 10686
(这给出了与 相同的结果hadoop fs -ls -R|wc -l
)
hadoop fs -text
也许最后一个问题是and本身的问题hadoop fs -cat
?或者我使用命名管道有问题吗?
答案1
我现在更多地不太确定这个版本:
#!/bin/bash
in=/tmp/grunt_in
out=/tmp/grunt_out
err=/tmp/grunt_err
if [ ! -p $in ]
then
mkfifo $in
mkfifo $out
mkfifo $err
{ script -q -c "pig 1>$out 2>$err" <>$in; rm $in $out $err; } &
fi
{
echo "fs $*"
echo
echo "-- end"
} >$in
cat $err >&2 &
catpid=$!
sed -n -u '/^grunt> -- end/q;/^grunt>/d;p' <$out
kill $catpid
所以我只是在命令内部重定向 stderr script
。我还用大括号替换了圆括号,并删除了 ,disown
因为我没有看到这样做有任何好处。我还$err
用 FIFO 进行了替换,以便能够尽早输出它,但这也增加了杀死cat
.
到目前为止效果还不错除了当我通过管道截断输出时,head
我会在下一个命令中得到截断或额外的输出。显然我需要一种方法来正确刷新命名管道。如果有人有任何提示,我会很高兴。