1

I run archey in my .zshrc. Problem is, due to displaying the current IP, it can sometimes run like two seconds. To make this less noticeable, I put it in the background like this:

# .zshrc
archey &
# lots of foo
wait

This way, it can fetch the IP while lots of other stuff is done in my zshrc. But now zsh displays the job and process id, and that archey finished every time:

Last login: Mon Jul 10 11:12:07 on ttys002
[1] 40436

# archey output

[1]  + done       archey

~
❯

As the doc states this is being sent to stderr, I tried using 2>/dev/null, without success.

How can I remove these two lines?

2

Zsh provides the MONITOR and NOTIFY options, and you can disable them to silence status report of background jobs.

() {
  setopt LOCAL_OPTIONS NO_NOTIFY NO_MONITOR
  archey &
  # ...
  wait
}
1

These two lines are output to stderr of the shell, not of the process. You can't make them disappear from zsh.

Realizing from the comments, that you want to see the output displayed, you need to go three steps:

  1. To avoid the noise of starting archey in the background, you must start it from a script
  2. To communicate the results of archey back to the main script, you must use a tempfile or something similar
  3. To understand, when it has finished, you can't use wait as it depends on the noisy background start

wrap-archey.sh:

#/bin/sh
archey >"$1" 2>&1
rm "$2"

start-archey.sh:

/path/to/wrap-archey.sh "$1" "$2" >/dev/null 2>&1 &

.zshrc:

ARCHEYOUT=$(mktemp)
ARCHEYFLAG=$(mktemp)
/path/to/start-archey.sh "$ARCHEYOUT" "$ARCHEYFLAG" >/dev/null 2>&1
#
# lots of foo
#
while test -f "$ARCHEYFLAG"; do sleep 0.1 ; done
cat "$ARCHEYOUT"
rm "$ARCHEYOUT"

wrap-archey.sh will redirect the output into a tempfile, and when done remove a flagfile. This is needed for the back communication.

start-archey.sh will start wrap-archey.sh in the background, eliminating the noise in the main script and returning immediately.

.zshrc will set up flagfile and resultfile, run start-archey.sh silently in the background, then do foo, then wait for archey to complete by polling the flagfile. Then it cleans up.

  • Unfortunately, this works only halfway. This gets rid of the noise, but now the shell can't wait for archey to finish at the end of .zshrc, so it often gets printed after the prompt. – Dikti Jul 10 '17 at 9:57
  • I mistyped archey & >/dev/null 2>&1 instead of archey >/dev/null 2>&1 & - try the edited version – Eugen Rieck Jul 10 '17 at 10:19
  • Still won't help the zsh with waiting. Also, putting stdout to /dev/null will obviously cause archey to not show at all, I only used 2>/dev/null. – Dikti Jul 10 '17 at 10:28
  • I didn't realize, that archey creates output you want to see - edited my answer. – Eugen Rieck Jul 10 '17 at 11:07
  • Thank you. Didn't realize it would be that much work, but now it works just fine! – Dikti Jul 10 '17 at 11:35
1

If you don't want to use a subshell, you can use:

# Run the command given by "$@" in the background
silent_background() {
  if [[ -n $ZSH_VERSION ]]; then  # zsh:  https://superuser.com/a/1285272/365890
    setopt local_options no_notify no_monitor
    # We'd use &| to background and disown, but incompatible with bash, so:
    "$@" &
  elif [[ -n $BASH_VERSION ]]; then  # bash: https://stackoverflow.com/a/27340076/5353461
    { 2>&3 "$@"& } 3>&2 2>/dev/null
  else  # Unknownness - just background it
    "$@" &
  fi
  disown &>/dev/null  # Close STD{OUT,ERR} to prevent whine if job has already completed
}

Then:

silent_background archey #  Or whatever command you want to background
0

This should work without additional script files:

tmpf=`mktemp`
{ archey ; echo 1 > "$tmpf" ; } &|

# foo

while [ ! -s "$tmpf" ] ; do sleep 0.1 ; done
rm "$tmpf"
unset tmpf

The key is &| operator. It runs the given command in background, but the command is not a job, so your display is not spammed. You cannot use wait though. I used a temporary file to detect if archey has finished.

If your # foo also produces output, you may experience a race condition. In this case it's reasonable to capture archey output to another temporary file (like in this other answer) and print it at the end.

I don't recommend using single temporary file for archey output and as a trigger. If you do this then while test may return true when archey still writes to the file, I think.

  • Makes it easier, thanks. I got rid of another line by removing the temp file in line 2 instead of echoing into it, and testing for existence in the while. – Dikti Jul 10 '17 at 11:47
  • @Dikti I gave it a thought before, it's flawed. Another (even well-behaved) program can create a new temporary file with the same name after you remove the old one and before your while starts. This is almost impossible but it can happen and you cannot prevent it. If it happens then your script will loop, maybe endlessly. My way is better because well-behaved programs don't write to random files not created by them. – Kamil Maciorowski Jul 10 '17 at 12:08

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.