【问题标题】:Why does grepping the same manpage sometimes results in an error?为什么 grepping 相同的联机帮助页有时会导致错误?
【发布时间】:2018-05-21 04:04:58
【问题描述】:

完全相同的命令:

man curl | grep -Pzo 'EXIT CODES(.|\n)*AUTHORS' | grep '  6  '

有时会给出预期的输出:

       6      Couldn't resolve host. The given remote host was not resolved.

有时会报错:

Binary file (standard input) matches

例如:

$ man curl | grep -Pzo 'EXIT CODES(.|\n)*AUTHORS' | grep '  6  '
       6      Couldn't resolve host. The given remote host was not resolved.

$ man curl | grep -Pzo 'EXIT CODES(.|\n)*AUTHORS' | grep '  6  '
Binary file (standard input) matches

$ man curl | grep -Pzo 'EXIT CODES(.|\n)*AUTHORS' | grep '  6  '
Binary file (standard input) matches

$ man curl | grep -Pzo 'EXIT CODES(.|\n)*AUTHORS' | grep '  6  '
       6      Couldn't resolve host. The given remote host was not resolved.

相关包的版本:

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 16.04.1 LTS
Release:        16.04
Codename:       xenial

$ grep --version
grep (GNU grep) 2.25
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Mike Haertel and others, see <http://git.sv.gnu.org/cgit/grep.git/tree/AUTHORS>.

$ man --version
man 2.7.5

$ curl --version
curl 7.47.0 (x86_64-pc-linux-gnu) libcurl/7.47.0 GnuTLS/3.4.10 zlib/1.2.8 libidn/1.32 librtmp/2.3
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp smb smbs smtp smtps telnet tftp
Features: AsynchDNS IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz TLS-SRP UnixSockets

我真的为这个而摸不着头脑。

我通过将-a 标志放入我的 grep 中解决了我的问题:man curl | grep -Pzoa 'EXIT CODES(.|\n)*AUTHORS' | grep -a ' 6 '

但我真的很困惑为什么有时它只会出错?...

【问题讨论】:

    标签: bash shell curl grep manpage


    【解决方案1】:

    因为使用了-z 选项,所以第一个 grep 将一个 NUL 字符附加到输出的末尾。接下来会发生什么取决于缓冲的变幻莫测。如果第二个 grep 在分析文件之前看到该 NUL,则它确定该文件是二进制文件。如果没有,它会找到您想要的匹配项。

    所以,这恰好对我有用:

    $ man curl | grep -Pzo 'EXIT CODES(.|\n)*AUTHORS' | grep '  6  '
           6      Couldn't resolve host. The given remote host was not resolved.
    

    但是,如果我将第一个 grep 的输出放在一个临时文件中并要求第二个 grep 读取它,那么第二个 grep 总是会抱怨输入是二进制的:

    $ man curl | grep -Pzo 'EXIT CODES(.|\n)*AUTHORS' >tmpfile;  grep '  6  ' tmpfile
    Binary file tmpfile matches
    

    替代方案:使用 awk

    避免 NUL 字符问题以及减少所需进程数量的一种方法是使用 awk:

    $ man curl | awk '/EXIT CODES/,/AUTHORS/{if (/   6   /) print}'
           6      Couldn't resolve host. The given remote host was not resolved.
    

    替代方案:使用 sed

    $ man curl | sed -n '/EXIT CODES/,/AUTHORS/{/   6   /p}'
           6      Couldn't resolve host. The given remote host was not resolved.
    

    替代方案:使用 greps 和 tr

    正如tripleee 建议的那样,另一种选择是使用tr 将NUL 替换为换行符:

    $ man curl | grep -Pzo 'EXIT CODES(.|\n)*AUTHORS' | tr '\000' '\n' | grep '  6  '
           6      Couldn't resolve host. The given remote host was not resolved.
    

    【讨论】:

    • 或者你可以用tr把NUL变成一个换行符。
    • @tripleee 非常好。谢谢你。我刚刚在答案中添加了tr 方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多