使用 grunt shell 从 bash 进行通信

Dav*_*aro 6 bash shell-script fifo

我厌倦了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
Run Code Online (Sandbox Code Playgroud)

当然,不仅输入必须发送到脚本,而且脚本的输出必须重定向到我当前的 bash 会话。我在这里使用/tmp/grunt_in/tmp/grunt_outFIFO 来实现这一点。为了确定何时pig处理命令,我发送了一条"-- end"评论并在sed正在监听输出的命令中检测到它,以使其在遇到end令牌时退出,并通过跳过所有grunt>提示仅输出相关部分。

请注意,<>$in即使我将输出重定向到$out以防止猪在第一个命令后退出,我也必须附加输入 FIFO 。我不知道确切的原因,但我认为它是这样工作的。

这实际上已经很好用了。例如

$ 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
Run Code Online (Sandbox Code Playgroud)

(我dfs在这里调用了我的脚本。)只剩下两个我目前无法弄清楚的问题:

  1. 当我第一次调用脚本时(即当 fifo/tmp/grunt_in尚不存在并且 pig 实例在后台启动时)我的终端设置不知何故搞砸了。我不再收到我的输入的回声,所以我必须reset盲目地输入 a才能恢复正常的终端。不过,成功的呼叫工作正常。
  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
    
    Run Code Online (Sandbox Code Playgroud)

    请注意text: Unable to write to output stream.此处的错误消息不是来自pig而是fs -text来自hadoop. 有时它会在前 9 或 10 行处被截断,如此处或有时在中间的某处。这很奇怪。我也试图发送手动命令/tmp/grunt_in和阅读/tmp/grunt_outcat,具有相同的结果,但是这证明我的分析sed不可能是这里的问题。一般来说,这似乎也不是大输出的问题,例如对于长目录列表,它工作正常:

    $ dfs -ls -R|wc -l
    10686
    
    Run Code Online (Sandbox Code Playgroud)

(这给出了与 相同的结果hadoop fs -ls -R|wc -l

也许最后一个问题是hadoop fs -texthadoop fs -cat它本身的问题?或者我使用命名管道有什么问题?

Dav*_*aro 2

我现在更多地不太确定这个版本:

#!/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
Run Code Online (Sandbox Code Playgroud)

所以我只是在命令内部重定向 stderr script。我还用大括号替换了圆括号,并删除了 ,disown因为我没有看到这样做有任何好处。我还$err用 FIFO 进行了替换,以便能够尽早输出它,但这也增加了杀死cat.

到目前为止,这工作得相当好,除了当我通过管道截断输出时,head我在下一个命令中得到截断或额外的输出。显然我需要一种方法来正确刷新命名管道。如果有人有任何提示,我会很高兴。