如何在“do”之后管道while循环输入到封装命令

时间:2014-10-05 09:22:52

标签: bash curl while-loop pipe stderr

我的目的是在下载文件时抓取(然后修改)cURL输出。

    curl -# -L --user-agent 'Mozilla/5.0' -o "`echo -e "$filename"`" "$url" 2>&1 |
    while true
    do
        read <&1 line1 line2
        echo $line2
            if [ "`echo $line2 | grep -o "#"`" = "#" ] ; then
                echo "downloading..."
                break
            elif [ "`echo $line2 | grep -o "curl"`" = "curl" ] ; then
                echo $line2
                break
            else
            echo "stderr still empty"    
            fi
    done

问题是cURL输出(发送到stderr)是动态的,所以我想我必须使用while true直到可以读取内容,因为如果我立即通过while read curl,管道是空的。

知道我想直接将curl输出发送到上面构造中的读取输入。

我真的不想使用任何临时文件(这很容易解决这个问题我同意:))

编辑:这是存储在日志中的stderr上的curl动态curl输出:

 
######################################################################## 100.0%
                                                                           0.2%
                                                                           0.5%
                                                                           1.1%
#                                                                          1.6%
#                                                                          2.6%
##                                                                         3.3%
###                                                                        4.6%
####                                                                       6.1%
####                                                                       6.5%
####                                                                       6.8%
#####                                                                      7.3%
#####                                                                      7.7%
#####                                                                      8.0%
#####                                                                      8.2%
######                                                                     8.7%

1 个答案:

答案 0 :(得分:3)

如果您想报告&#34;下载...&#34;当curl正在下载时,你可能想要做这样的事情(注意 - 有点高级bash hacking):

curl "$url" -o "$outfile" -vs > >( # redirect stdout to sub-shell, note the space
  # parse curl's "verbose" output which tells us what is happening
  # while we use -s to silence the standard progress bar which is useless for this
  while read line; do # read verbose progress messages
    if grep -q "Connected" <<<"$line"; then # wait for curl to connect
      echo "Downloading..."
      break
    fi
  done
  cat > /dev/null # make sure to consume all stdin if we break early, to prevent "broken pipe"
) 2>&1 || echo "Error!"

我使用进程替换将输出定向到子shell的原因是不丢失curl退出代码,如果出现错误则该代码将为非零,允许我使用bash逻辑评估来报告错误(或我可以从$?捕获它并检查它 - curl有非常详细的退出代码报告,所以我可以找出退出代码出了什么问题。详情请咨询man curl

还要注意2>&1的位置,它将标准错误流重定向到标准输出流,以便进程替换可以获取通常发布到错误流的卷曲进度消息。这个重定向必须在stdout捕获之后,否则它只会创建一个stdout的副本,并且子shell将不会得到任何东西。关于流复制的Bash手册部分更好地解释了这一点。

关于您的代码的说明

上面的代码中有几个问题:

*)而不是

... -o "`echo $filename`" ...

你应该做的

... -o "$filename" ...

当你想要做的就是让bash扩展$filename作为-o参数的值时,没有理由进行额外的间接。

*)这没有道理:

read <&1

文件描述符1是标准输出 - 你真的不想从中读取。如果您想从标准输入读取,则无需重定向 - read默认情况下从标准输入读取。

*)这不是一个好习惯:

if [ "`echo $var | grep -o "value"`" == "value" ]; then

有很多原因 - 首先,grep -o几乎没用,尤其是简单的文本搜索,因为它只会输出您想要查找的内容(取决于是否找到了值),这些内容完全映射到grep退出代码为0或1.因此,只需执行if echo $var | grep -q "value"; then即可。如果grep成功,则此表达式将成功,否则将失败。 -q用于使输出静音,因为您不需要它(只要它成功或不成功)。此外,如果您在变量中包含文本,则使用echo将其移至grep只会令人讨厌(它会打开子shell和分叉),而是说grep -q "value" <<<"$var"。< / p>

最后,关于报告curl是否正在下载,我个人认为curl进度指标已经足够好了,但如果不是,那么只需用-s将其静音。< / p>