使用 2>&1 仅将 stdout/stderr 定向为 BASH 脚本中许多命令中的单个命令

使用 2>&1 仅将 stdout/stderr 定向为 BASH 脚本中许多命令中的单个命令

第一次发帖,请多多包涵:)

我正在编写我的第一个 BASH 脚本,并使用 systemd 在计时器上调用它(也是我的第一个 systemd 单元!)。该脚本每天运行备份,并使用通知发送将通知发送到我的桌面。

我想将一些额外的日志记录定向到journalctl,但仅限于某些特定的单个命令。我用了 2>&1:

df -h | grep --color=never /mnt/Backups 2>&1

但是当我这样做时,无论备份成功还是失败,通过通知发送的桌面通知都会显示“成功”(systemd 完成正常)。我已经测试过删除 2>&1 和 notification-send 为我提供了脚本的 Borg 操作部分的正确通知建议(成功和失败都经过测试)。

那么 - 我如何开始然后停止该重定向,让它显示在journalctl中,并准确显示我的通知?

这是我的脚本的一部分:

df -h | grep --color=never /mnt/Backups 2>&1

SUCCESS=$?
echo $SUCCESS

## Use DESTOP Notifications.
if [ "${SUCCESS}" = "0" ]; then
notify-send -a Borg 'Operation was successful!' '~/.local/bin/borg-backup.sh' -u normal -i checkbox-checked-symbolic
else
notify-send -a Borg 'Operation was *NOT* successful' '~/.local/bin/borg-backup.sh' -u critical -i dialog-error
exit 1
fi 

谢谢 :)

答案1

首先,我假设您希望 grep 的输出发送到 stderr? 2>&1 将 stderr 重定向到 stdout。您可能需要 grep 1>&2。

其次,重定向仅适用于该单个命令。它不会持续存在,因此启动和停止重定向不是问题。

第三,我没有得到:“成功”(systemd 完成得很好)。您所测试的只是 df -h 的输出提到 /mnt/Backups。其他一些事情可能会破坏这个过程。

第四,管道中进程的状态有时是意想不到的。每个进程的状态都记录在数组 PIPESTATUS 中。整个管道的状况很复杂。特别是,带有重定向的管道可以在子 shell 中执行(因此主 shell 保持其流不变)。在这种情况下,我准备相信您的成功与子 shell 本身的退出状态有关,而不是与管道中的最后一个命令有关。

我对这些东西很模糊,因为我对它不够信任,无法自己使用它。我对此的看法是检查文本,而不是状态,例如:(未经测试):

MOUNT="$( df -h | grep --color=never /mnt/Backups )"
echo 1>&2 "Mount test gets ${MOUNT:-Nothing}"

if [[ "${MOUNT}" = "/mnt/Backups" ]]; then ...

这种东西很难诊断。我正在学习使用RC=$?保存命令状态、echo $?显示命令状态、declare -p PIPESTATUS显示状态数组和RP="$( declare -p PIPESTATUS )"保存状态数组。

问题是所有这四个(包括对变量的赋值)也是命令,并导致状态重置为零。因此,您永远无法通过多个途径看到您的初始命令状态。状态是短暂的,数据是永恒的。

我最好的机制是让 grep 计算与 的匹配项grep -c,并将返回的计数保存在变量中。您不必丢弃文件名,因为如果 grep 读取标准输入,它不会输出名称。

作为大文件的改进,请使用grep -l.当它看到第一个匹配项时退出(grep -c必须继续计数到最后)。grep -l输出包含匹配项的文件名,因此测试针对"", 或"(standard input)"

相关内容