从 bash 与 grunt shell 进行通信

从 bash 与 grunt shell 进行通信

我厌倦了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_outFIFO 来实现这一点。为了弄清楚何时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。)目前只剩下两个我无法解决的问题:

  1. 当我第一次调用该脚本时(即 fifo/tmp/grunt_in尚不存在且 pig 实例在后台启动时),我的终端设置不知何故被搞乱了。我再也得不到输入的回显,所以我必须盲目地输入reset才能恢复正常的终端。但后续调用工作正常。
  2. 当我尝试在 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命令 from hadoop。有时它会在前 9 或 10 行被截断,就像这里一样,有时会在中间的某个地方被截断。这很奇怪。我还尝试手动将命令发送到/tmp/grunt_in并读取/tmp/grunt_outwith cat,得到相同的结果,但这证实了我的解析 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我会在下一个命令中得到截断或额外的输出。显然我需要一种方法来正确刷新命名管道。如果有人有任何提示,我会很高兴。

相关内容