4

I'm trying to pipe a bar script into lemonbar in bspwm.

In my bspwmrc I have:

~/.config/bspwm/lemonbar.sh | lemonbar -p 

lemonbar.sh contains:

#!/bin/bash

clock() {
    date +%H:%M:%S
}

while true; do
    echo "%{c}$(clock)"
    sleep 1;
done

Everything works as expected, except when I exit bspwm I get:

line 12: echo: write error: Broken pipe

Obviously the error has something to do with the echo on line 12 but I can't figure out exactly what

2 Answers 2

0

I was unable to reproduce this issue. For me it is working. Make sure you put the script line at the end of bspwmrc and add a & at the end. You can see it working here.

I have my own setup with lemonbar. See at the top of the screen, time is echoed from your script and whenever I restart/exit from bspwm, I don't get some errors.

0

Normally, when a process writes to a pipe without reader, that process receives a SIGPIPE signal and dies. If the process is configured to ignore the SIGPIPE, instead it doesn't die but the write() returns with a EPIPE error for which the corresponding error message is Broken pipe in English locales.

bash's echo builtin will report that error in that case:

$ (trap "" PIPE; bash -c 'sleep 1; echo foo' | true)
bash: line 1: echo: write error: Broken pipe

So it looks like what's happening in your case: your script has been run in an environment where SIGPIPE is ignored (not a wise thing to do in general).

Looking at bspwm's source code, that's exactly what it does. The fact that it doesn't restore SIGPIPE's default disposition when running commands could be seen as a bug that you may want to report.

To restore SIGPIPE's disposition to its default yourself to work around that bspwm bug, you could use trap - PIPE, but not in the bash shell, as bash honours that annoying and nonsensical POSIX requirement that signals cannot be un-ignored if they were ignored on startup.

Signals that were ignored on entry to a non-interactive shell cannot be trapped or reset, although no error need be reported when attempting to do so. An interactive shell may reset or catch signals ignored on entry. Traps shall remain in place for a given shell until explicitly changed with another trap command.

So you'd need to switch to a different shell that doesn't such as zsh:

#! /bin/zsh -
trap - PIPE
while true; do
    print -P '%%{c}%*'
    sleep 1
done

(also using one of zsh's builtin ways to print the current time).

Or handle the echo failure:

#! /bin/bash -

clock() {
  date +%T
}

while true; do
  echo "%{c}$(clock)" 2> /dev/null || exit
  sleep 1
done

Note that if you had used date +%%{c}%T, as date is not a builtin in bash nor zsh, it's the process running date that would get the SIGPIPE when the pipe becomes broken, so you'd need to handle the error in that case whether SIGPIPE is ignored or not:

#! /bin/bash -
while true; do
  date +%%{c}%T 2> /dev/null || exit
  sleep 1
done

If SIGPIPE is ignored, the script will exit because date reported a write() error (and exit normally with $? being something like 1), and if not, because date was killed (with $? being something like 141).

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.