0

My first post, please be kind :)

I'm writing my first ever BASH script, and using systemd to invoke it on a timer (my first systemd units too!). The script runs backups daily, and uses notify-send to send Notifications to my Desktop.

I would like to direct some extra logging to journalctl, but only for some specific individual commands. I used 2>&1:

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

But when i do this, whether the backup succeeds or fails, the desktop notification via notify-send says "success" (systemd completes fine). I've tested removing the 2>&1 and notify-send gives me the correct notification advice of the Borg operations portion of the script (both success and fail were tested).

So - how do i start and then stop that redirection, have it show in journalctl, and have my notifications accurately displayed?

Here's that portion of my script:

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 

Thanks :)

1 Answer 1

1

First, I assume you want the output from grep to go to stderr? 2>&1 redirects stderr to stdout. You probably want grep 1>&2.

Second, redirection will only apply to that single command. It does not persist, so start and stop the redirection is not an issue.

Third, I don't get: "success" (systemd completes fine). All you are testing is that the output from df -h mentions /mnt/Backups. Some other thing could be breaking the process.

Fourth, the status of processes in pipelines is unexpected at times. Each process gets its status recorded in an array PIPESTATUS. The status of the pipeline as a whole is complex. In particular, a pipeline with a redirection may be executed in a subshell (so the main shell retains its streams unchanged). In that case, I am ready to believe that your SUCCESS is related to the exit status of the subshell itself, rather than the last command in the pipeline.

I'm hazy about this stuff because I don't trust it enough to use it myself. My take on this would be to check text, not status, like: (untested):

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

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

This stuff is seriously hard to diagnose. I am learning using RC=$? to save the command status, echo $? to show the command status, declare -p PIPESTATUS to show the array of status, and RP="$( declare -p PIPESTATUS )" to save the array of status.

The issue is that all four of those (including the assignments to variable) are also commands, and result in the status being reset to zero. So you can never see your initial command status by more than one route. Status is ephemeral, data is forever.

My best mechanism is to get grep to count matches with grep -c, and save the returned count in a variable. You don't have to discard the filename, because if grep reads stdin it does not output a name.

As a refinement for large files, use grep -l. This exits when it sees the first match (grep -c has to keep counting to the end). grep -l outputs the filename containing the match, so the test is for "", or "(standard input)".

1
  • I supplied just a portion of the script. The script is running Borg Backups, with a disk-space check thrown in. I'm not trying to notify-send the disk check - i'm trying to notify-send the Borg backup portion. But when i include the 2>&1, the RC of the Borg portion of the script is ignored when passing the $SUCCESS to notify-send. As long as systemd completes, it passes as successful, even if Borg crashed and burned. If i do not include the 2>&1 then the disk-space info is not sent to journalctl - but the $SUCCESS portion correctly outputs (success or fail) depending on how Borg went. Commented Dec 30, 2019 at 20:57

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.