1

I have this in /etc/init.d/unicorn

#!/bin/bash
# /etc/init.d/unicorn

# ### BEGIN INIT INFO
# chkconfig: 2345 95 016
# processname: unicorn
# dscription: Stop/start unicorn
### END INIT INFO

export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

cmd() {
    cd /vagrant
    unicorn -p 3000 -D
}

# Start the service
start() {
    su - vagrant -c cmd
}

### main logic ###
case "$1" in
    start)
        start
        ;;
    *)
        echo $"Usage: $0 {start}"
        exit 1
esac

exit 0

I am trying to start unicorn in my local rails folder. I feel like this command should work:

su - vagrant -c cmd

and cannot figure out the reason.

Eric Francis
  • 23,039
  • 31
  • 88
  • 122
  • 1
    why are you exporting `PATH` without a reference to `$PATH`? Why are you using `su` to run a command? Use `sudo`. Or use `sudo -s` at start of script so that you become root. Or better yet, just always run the script as root. – Alexej Magura Feb 26 '14 at 00:50
  • 2
    @AlexejMagura This is an init script. It always runs as root. He uses su because he wants a command to run as a non-root user. – that other guy Feb 26 '14 at 01:22

2 Answers2

1

I guess you are under the impression that the shell function cmd which is defined in that script should be available in the shell which has started that script earlier.

This is wrong, unless you sourced that script (which is unusual for scripts in /etc/init.d/). When you start a script (not source it), then you start a second process which executes the script. All definitions of shell functions (like that cmd) are valid only within that shell script and die with the process.

In case you really want the cmd to be available, you will have to source the script unicorn:

source /etc/init.d/unicorn

The su command, however, will still not be able to call that shell function because it only can call executables it can start using exec(), so they need to be a file. A shell function isn't.

Alfe
  • 56,346
  • 20
  • 107
  • 159
0

To fix this, inline the function in the shell invoked by su:

start() {
    su - vagrant -c 'cd /vagrant && unicorn -p 3000 -D'
}

and as for figuring out the reason in the first place, tooling is helpful:

$ shellcheck unicorn

In unicorn line 19:
    su - vagrant -c cmd
                    ^-- SC2033: Shell functions can't be passed to external commands.
that other guy
  • 116,971
  • 11
  • 170
  • 194