【问题标题】:Pipe Find command "stderr" to a command管道查找命令“stderr”到命令
【发布时间】:2012-03-19 21:33:00
【问题描述】:

您好,我有一个特殊的问题,我正在努力找到(双关语)解决方案。

$> find ./subdirectory -type f 2>>error.log

我从该命令中收到类似“find: ./subdirectory/noidea: Permission denied”的错误,这将被重定向到 error.log。

在重定向到 error.log 之前,有什么方法可以将 stderr 传递到另一个命令?

我希望能够做类似的事情

$> find ./subdirectory -type f 2 | sed "s#\(.*\)#${PWD}\1#" >> error.log

我只想将 stderr 传递到 sed 命令并获取 find 命令错误 的整个路径。

我知道管道在这里不起作用,可能不是正确的方式。

我的问题是我需要 stdout 和 stderr 两者都必须同时通过不同的东西进行处理。

编辑: 好的。对我的问题稍作修改。

现在,我有一个 shell 脚本,solve_problem.sh

在这个 shell 脚本中,我有以下代码

ErrorFile="error.log"
for directories in `find ./subdirectory -type f 2>> $ErrorFile`
do
    field1=`echo $directories | cut -d / -f2`
    field2=`echo $directories | cut -d / -f3`
done

同样的问题,但在 shell 脚本中。 “find: ./subdirectory/noidea: Permission denied” 错误应该进入 $ErrorFile 并且 stdout 应该分配给变量 $directories .

【问题讨论】:

    标签: unix find pipe io-redirection


    【解决方案1】:

    同时管道 stderr 和 stdout - 想法来自this post:

    (find /boot | sed s'/^/STDOUT:/' ) 3>&1 1>&2 2>&3 | sed 's/^/STDERR:/'
    

    样本输出:

    STDOUT:/boot/grub/usb_keyboard.mod
    STDERR:find: `/boot/lost+found': Brak dostępu
    

    像 3>&1 1>&2 2>&3 这样的 Bash 重定向交换标准错误和标准输出。

    我会将您的示例脚本修改为如下所示:

    #!/bin/bash
    ErrorFile="error.log"
    (find ./subdirectory -type f 3>&1 1>&2 2>&3 | sed "s#^#${PWD}: #" >> $ErrorFile) 3>&1 1>&2 2>&3 | while read line; do
        field1=$(echo "$line" | cut -d / -f2)
        ...
    done
    

    请注意,我交换了 stdout 和 stderr 两次。

    附加的小评论 - 查看查找手册页中的 -printf 选项。可能对你有用。

    【讨论】:

    • 这是一种有用的技术,但应该小心。特别是,您现在看到 find 的错误消息以“STDERR:”为前缀写入标准输出,而 find 的标准输出以“STDOUT:”为前缀写入标准错误,这可能会造成混淆。
    • @kupson:确实非常方便的解决方案。但我不确定它是否适用于我的场景。我尝试了(find ./subdirectory/ -type f) 3>&2 2>&1 1>&3 | sed "s?^\(find: \)\(.*\)?\1${PWD}/\2?" >> $ErrorFile 之类的方法,但这对我不起作用。错误以我想要的方式重定向到日志文件,但 stdout 没有分配给 for 循环中的变量(我已经更新了我的问题)
    • @latestVersion 在这种情况下我会使用 'while' 循环。
    【解决方案2】:

    如果您需要将stderr 重定向到stdout 以便管道中的以下命令将其作为输入,那么您可以使用2>&1。

    有关更多信息,请查看all about redirection 操作指南。

    编辑:即使您需要在管道中进一步编辑 pass stdout,您也可以使用 sed 过滤错误消息并将它们写入文件:

    $ find . -type f 2>&1 | sed '/^find:/{
    > w error.log
    > d
    > }'
    

    在这个例子中:

    • 在find 命令中stderr 被重定向到stdout
    • 在find 中与正则表达式匹配的sed 命令错误将写入文件 (w error.log) 并从输出中删除 (d)。
    • 管道后面的管道中的任何命令都将接收来自find 的输出。

    注意:这将与来自find 的所有错误消息以find: 开头一样有效。否则,应修改sed 中的正则表达式以正确匹配所有情况。

    【讨论】:

    • 在我的情况下,管道本身是没有问题的,因为我希望 stderr 通过“sed”命令,而 stdout 通过不同的我的脚本中的一组命令。
    • 我不完全确定这是如何工作的。也许你可以帮助我了解这里发生了什么。我也可以在sed 命令中替换吗??
    • 我已经编辑了解释以使其更清晰。我希望它有所帮助。
    【解决方案3】:

    你可以试试这个(在 bash 上),它似乎可以工作:

    find ./subdirectory -type f 2> >(sed "s#\(.*\)#${PWD}\1#" >> error.log)
    

    执行以下操作:

    1. 2> 将标准错误重定向到
    2. >(...) 进程替换(运行 sed,附加到 error.log)

    【讨论】:

    • 此解决方案适用于命令行。但是当我在 shell 脚本中尝试它时,我遇到了语法错误。无论如何,你可以帮我解决这个问题吗?
    • @latestVersion:我刚刚在发布时尝试了该行(在 bash 4.2.20 上),它似乎可以工作。请注意,2> 之后必须有一个空格,否则会出现语法错误。 (实际上>(...)之前需要有一个空格,但在这种情况下是一样的。)
    猜你喜欢
    • 1970-01-01
    • 2019-10-12
    • 2016-04-17
    • 2012-06-26
    • 1970-01-01
    • 1970-01-01
    • 2012-06-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多