-1

I have a BASH script that runs fine in terminal. But when I try to get it to run on startup, nothing happens. It seems related to the fact that the script uses functions. When I break the commands out of functions, it works as expected on startup. Any thoughts on why? Here is an example, but any arbitrary code in the function creates the same issue:

 #!/bin/bash

say-stuff () {

notify-send Stuff "Here is some stuff." 

}

say-stuff

Linter
  • 159
  • How are you setting it to run on startup and where is notify-send being set? – jesse_b Apr 16 '22 at 18:33
  • Is notify-send available in $PATH in the environment where the script is being executed? Are you expecting to be able to notify a particular user with a graphical pop-up at boot time? How are you running your script at startup and what does the script output (error messages etc.; you can see these if you redirect the error stream to a file)? – Kusalananda Apr 16 '22 at 18:41
  • I just put that notify-send command there for a minimal working example. But any command has the same issue. The script is located in ~/user/.local/bin and I am using the "Startup Applications" under Pop!_OS to run the script. And it works as expected if I 1) run it from terminal or 2) alter the script to remove the functions and leave the commands. It seems that the functions are at issue. – Linter Apr 16 '22 at 19:15

2 Answers2

2

There is a space before the shebang in your script - which breaks the file magic:

$ printf '#!/bin/bash\n' | file -
/dev/stdin: Bourne-Again shell script, ASCII text executable

but

$ printf ' #!/bin/bash\n' | file -
/dev/stdin: ASCII text

This causes the XDG autostart mechanism to fall back to executing the script with /bin/sh, in which say-stuff isn't a valid function name:

$ sh -c 'say-stuff () { echo "stuff"; }'
sh: 1: Syntax error: Bad function name

You can see this happening if you run xdg-autostart in an interactive terminal with a minimal .desktop file:

$ cat ~/.config/autostart/say-stuff.desktop 
[Desktop Entry]

Type=Application

Name=say-stuff

Exec=say-stuff

then

$ xdg-autostart 2>&1 | grep -A3 say-stuff
** Message: 18:23:33.620: xdg-autostart.vala:39: Processing /home/steeldriver/.config/autostart/say-stuff.desktop file.
** Message: 18:23:33.627: xdg-autostart.vala:94: Launching: say-stuff (say-stuff.desktop)
** Message: 18:23:33.627: xdg-autostart.vala:39: Processing /etc/xdg/autostart/nm-tray-autostart.desktop file.
/home/steeldriver/.local/bin/say-stuff: 3: Syntax error: Bad function name
** Message: 18:23:33.646: xdg-autostart.vala:94: Launching: nm-tray (nm-tray-autostart.desktop)
** Message: 18:23:33.646: xdg-autostart.vala:39: Processing /etc/xdg/autostart/upg-notifier-autostart.desktop file.
** Message: 18:23:33.655: xdg-autostart.vala:94: Launching: /usr/libexec/lubuntu-update-notifier/lubuntu-upg-notifier.sh (upg-notifier-autostart.desktop)

It "works" when you execute the script directly because

  • say-stuff is a legal function name in bash; and

  • your interactive shell is bash, and that causes the script with the invalid shebang to also run in bash

See also Which shell interpreter runs a script with no shebang?

steeldriver
  • 81,074
0

Jobs run through cron, or startup scripts aren't run in the same runtime environment that you have on your desktop. Startup scripts are run as root. None of your PATH changes, or other environment variable settings from ~/.bashrc are automatically propagated to your cron job. For example, there's no $DISPLAY, so GUI programs need special treatment (read man xhost).

One can set environment variables for all one's cron jobs in the crontab file Read man 5 crontab.

Look at the results of echo "=== id ===";id;echo "=== set ===";set;echo "=== env ===";env | sort;echo "=== alias ===";alias in each of your environments.

An easy way is to store the commands in a bash script, and execute it from your terminal session, saving the output, then, execute the script from the "other" environment, saving the output. Compare the saved outputs using diff.

#!/bin/bash
echo "=== id ===";id
echo "=== set ===";set
echo "=== env ===";env | sort
echo "=== alias ===";alias`
waltinator
  • 4,865
  • Waltinator, does this explain why the command runs outside of a function, but not in one at startup? – Linter Apr 16 '22 at 20:35
  • @Linter It would potentially explain why notify-send (or any command that needs access to a graphical interface) would fail to run when there is no GUI running. I'm noting that you still have not updated your question with information about how you run the script. – Kusalananda Apr 16 '22 at 22:46
  • First, from man notify-send: DESCRIPTION With notify-send you can send desktop notifications to the user via a notification daemon from the command line. These notifications can be used to inform the user about an event or display some form of information without getting in the user's way., so you have to find a "notification daemon". Second, do you understand that $PATH is a per-process, colon-separated list of directories to search for programs to run? And, @Kusalananda I have updated my answert – waltinator Apr 17 '22 at 00:01