0

I've looked at How do I run a 'sudo' command inside a script? but this seems to be a different issue.

I want to run a script to change from root to the mastodon user using su, run Rails commands, and then exit back to the root account and restart mastodon.

Manually, I can log into root via ssh [email protected] which gives me the root@Mastodon:~# shell. Then I use sudo su - mastodon to change to the mastodon account (I am not prompted for a password) and then cd live. Then I can run the Rails commands, etc., and they work, and then I can exit and run systemctl restart mastodon-*.

But my shell script to do the same thing doesn't work. The restartall script is

#!/bin/bash

sudo su - mastodon

cd live

RAILS_ENV=production bundle exec rake tmp:cache:clear

RAILS_ENV=production bundle exec rails assets:generate_static_pages

RAILS_ENV=production bundle exec rails assets:precompile

exit

systemctl restart mastodon-*

and I run it this way root@Mastodon:~# ./restartall

The terminal user and path change to mastodon@MyMastodon, but that's all; the script fails wth: ./restartall: line 5: cd: live: No such file or directory

I also tried root@Mastodon:~# sudo ./restartall

What am I doing wrong in using su to change to the mastodon user?

Will simply using exit correctly take the script back to root@Mastodon before systemctl restart mastodon-* ?

BlueDogRanch
  • 55
  • 1
  • 3
  • 17
  • Related: [after su, the script stops working](https://askubuntu.com/questions/1065842/after-su-the-script-stops-working) – steeldriver Feb 25 '23 at 21:43
  • Thanks, that's interesting. I tried `sudo su -c 'cd live' mastodon` and got "permission denied." – BlueDogRanch Feb 25 '23 at 21:52
  • Hmm ... well `su` and `su -` are not quite the same thing; you'd need `sudo su -c 'cd live' - mastodon` or (perhaps clearer) `sudo su -l -c 'cd live' mastodon` – steeldriver Feb 25 '23 at 21:59
  • Another option is to use a here-document to read commands into the su shell via standard input - but that will have issues if any of the commands read stdin themselves. See for example [how to write a script that will run commands after su, without using -c](https://unix.stackexchange.com/questions/155326/how-to-write-a-script-that-will-run-commands-after-su-without-using-c) – steeldriver Feb 25 '23 at 22:01
  • Ok, `sudo su - mastodon -c "cd live (bundle commands here) exit"` works and it exits correctly and runs `systemctl restart mastodon-*`, but throws "bundle: command not found" errors. – BlueDogRanch Feb 25 '23 at 22:08
  • Same "bundle: command not found" with `sudo su -l -c 'cd live RAILS_ENV=production bundle exec rake tmp:cache:clear RAILS_ENV=production bundle exec rails assets:generate_static_pages RAILS_ENV=production bundle exec rails assets:precompile exit' mastodon` – BlueDogRanch Feb 25 '23 at 22:18

1 Answers1

2

The reason this fails is that sudo su - mastodon starts a new interactive shell as user mastodon. Any commands that follow are not executed until that shell exits.

You could pass the commands to su via its -c option, as described in the previous question after su, the script stops working, so

#!/bin/bash

sudo su -l mastodon -c '
  cd live
  RAILS_ENV=production bundle exec rake tmp:cache:clear
  RAILS_ENV=production bundle exec rails assets:generate_static_pages
  RAILS_ENV=production bundle exec rails assets:precompile
'

systemctl restart mastodon-*

(you don't need an explicit exit at the end of the commands passed via -c since the non-interactive su shell will exit naturally when it runs out of commands to execute).

Alternatively, you could use a here-document to pass the commands to the su shell via standard input, as described in how to write a script that will run commands after su, without using -c but please note the warning about commands that themselves read from stdin.

However you could consider avoiding su altogether, and writing your script so that it checks who is running it, and re-executes itself as the target user if required, like

#!/bin/bash

rails_user=mastodon

if [[ $EUID -ne $(id -u $rails_user) ]]; then
  echo "Switching to user '$rails_user' to perform tasks"
  exec sudo -iu "$rails_user" "$(realpath $0)"
fi

cd live
# etc.
steeldriver
  • 131,985
  • 21
  • 239
  • 326
  • Thanks! The first example works. Though I'm still getting "bundle: command not found" errors even though the script completes, exits and runs `systemctl restart mastodon-*`; that must be a different issue? – BlueDogRanch Feb 25 '23 at 22:41
  • @BlueDogRanch that sounds like an issue with how `PATH` is set for user `mastodon`'s login shell - remember non-interactive bash shells don't process ~/.bashrc so you should be using ~/.bash_login or ~/.profile for things like that – steeldriver Feb 25 '23 at 22:46
  • Ok, I'm still learning shells. There is a .profile file, and with a file mod date in 2019, it obviously wasn't modified by the mastodon install. – BlueDogRanch Feb 25 '23 at 22:55