2

I've installed RVM via https://raw.githubusercontent.com/rvm/rvm/master/binscripts/rvm-installer

I'm on Ubuntu and I use Bash.

Once I install it, I need to be able to source ~/.rvm/scripts/rvm based on the installation instructions. I need to do this by executing a script via CLI (test.sh) which, in turn, calls a PHP script (test.php) that does the sourcing via shell commands. Once I do that, I get this error about builtin:

$ ./test.sh
sh: 10: /home/housni/.rvm/scripts/rvm: builtin: not found

This is test.sh running on Bash that calls test.php

#!/bin/bash
./test.php

This is test.php

#!/usr/bin/php -q
<?php
    passthru('. ~/.rvm/scripts/rvm');
?>

When I type source ~/.rvm/scripts/rvm directly in a terminal (bash) and execute it, I see no errors.

It seems to me like the RVM script is trying to execute dash instead of bash but that doesn't make complete sense either because the RVM script begins with #!/usr/bin/env bash.

Any idea what I'm doing wrong in my PHP script?

Here are the contents of ~/.rvm/scripts/rvm:

#!/usr/bin/env bash

# rvm : Ruby enVironment Manager
# https://rvm.io
# https://github.com/wayneeseguin/rvm

# partial duplication marker dkjnkjvnckbjncvbkjnvkj
# prevent from loading in sh shells
if
  builtin test -n "${BASH_VERSION:-}" -o -n "${ZSH_VERSION:-}" -o -n "${KSH_VERSION:-}"
then
  case "`uname`" in
    (CYGWIN*) __shell_name="`\command \ps -p $$ | \command \awk 'END {print $NF}'` 2>/dev/null" ;;
    (SunOS)   __shell_name="`\command \ps -p $$ -o comm=`" ;;
    (*)       __shell_name="`\command \ps -p $$ -o ucomm=`" ;;
  esac
  case "$__shell_name" in
    (""|dash|sh|ksh|*/dash|*/sh|*/ksh) return 0 ;; # silently stop in sh shells
  esac
  unset __shell_name
else
  return 0
fi

# also duplicated in scripts/base
__rvm_has_opt()
{
  if # pre-gnu
   [[ -n "${ZSH_VERSION}"  ]]
  then
    setopt | GREP_OPTIONS="" \command \grep "^${1}$" >/dev/null 2>&1 || return $?
  elif # mksh
    [[ -n "${KSH_VERSION}"  ]]
  then
    set +o | GREP_OPTIONS="" \command \grep "-o ${1}$" >/dev/null 2>&1 || return $?
  elif # bash
    [[ -n "${BASH_VERSION}" ]]
  then
    [[ ":$SHELLOPTS:" == *":${1}:"* ]] || return $?
  else # what is this?!
    return 1
  fi
}

# Do not allow sourcing RVM in `sh` - it's not supported
# return 0 to exit from sourcing this script without breaking sh
if __rvm_has_opt "posix"
then return 0
fi

# TODO: Alter the variable names to make sense
\export HOME rvm_prefix rvm_user_install_flag rvm_path
HOME="${HOME%%+(\/)}" # Remove trailing slashes if they exist on HOME

[[ -n "${rvm_stored_umask:-}" ]] || export rvm_stored_umask=$(umask)
if (( ${rvm_ignore_rvmrc:=0} == 0 ))
then
  rvm_rvmrc_files=("/etc/rvmrc" "$HOME/.rvmrc")
  if [[ -n "${rvm_prefix:-}" ]] && ! [[ "$HOME/.rvmrc" -ef "${rvm_prefix}/.rvmrc" ]]
  then rvm_rvmrc_files+=( "${rvm_prefix}/.rvmrc" )
  fi

  for rvmrc in "${rvm_rvmrc_files[@]}"
  do
    if [[ -f "$rvmrc" ]]
    then
      # pre-gnu
      if GREP_OPTIONS="" \command \grep '^\s*rvm .*$' "$rvmrc" >/dev/null 2>&1
      then
        printf "%b" "
Error:
        $rvmrc is for rvm settings only.
        rvm CLI may NOT be called from within $rvmrc.
        Skipping the loading of $rvmrc"
        return 1
      else
        source "$rvmrc"
      fi
    fi
  done
  unset rvm_rvmrc_files
fi

# duplication marker jdgkjnfnkjdngjkfnd4fd
# detect rvm_path if not set
if
  [[ -z "${rvm_path:-}" ]]
then
  if
    [[ -n "${BASH_SOURCE:-$_}" && -f "${BASH_SOURCE:-$_}" ]]
  then
    rvm_path="${BASH_SOURCE:-$_}"
    rvm_path="$( \command \cd "${rvm_path%/scripts/rvm}">/dev/null; pwd )"
    rvm_prefix=$( dirname $rvm_path )
  elif
    [[ "${UID:-}" == "0" || "${USER:-}" == "root" ]]
  then
    if
      (( ${rvm_user_install_flag:-0} == 0 ))
    then
      rvm_prefix="/usr/local"
      rvm_path="${rvm_prefix}/rvm"
    else
      rvm_prefix="$HOME"
      rvm_path="${rvm_prefix}/.rvm"
    fi
  else
    if
      [[ -d "$HOME/.rvm" && -s "$HOME/.rvm/scripts/rvm" ]]
    then
      rvm_prefix="$HOME"
      rvm_path="${rvm_prefix}/.rvm"
    else
      rvm_prefix="/usr/local"
      rvm_path="${rvm_prefix}/rvm"
    fi
  fi
else
  # remove trailing slashes, btw. %%/ <- does not work as expected
  rvm_path="${rvm_path%%+(\/)}"
fi

# guess rvm_prefix if not set
if [[ -z "${rvm_prefix}" ]]
then
  rvm_prefix=$( dirname $rvm_path )
fi

# duplication marker kkdfkgnjfndgjkndfjkgnkfjdgn
[[ -n "${rvm_user_install_flag:-}" ]] ||
case "$rvm_path" in
  (/usr/local/rvm)         rvm_user_install_flag=0 ;;
  ($HOME/*|/${USER// /_}*) rvm_user_install_flag=1 ;;
  (*)                      rvm_user_install_flag=0 ;;
esac

export rvm_loaded_flag
if [[ -n "${BASH_VERSION:-}" || -n "${ZSH_VERSION:-}" ]] &&
  \typeset -f rvm >/dev/null 2>&1
then
  rvm_loaded_flag=1
else
  rvm_loaded_flag=0
fi

if
  (( ${rvm_loaded_flag:=0} == 0 )) || (( ${rvm_reload_flag:=0} == 1 ))
then
  if
    [[ -n "${rvm_path}" && -d "$rvm_path" ]]
  then
    true ${rvm_scripts_path:="$rvm_path/scripts"}

    if
      [[ ! -f "$rvm_scripts_path/base" ]]
    then
      printf "%b" "WARNING:
      Could not source '$rvm_scripts_path/base' as file does not exist.
      RVM will likely not work as expected.\n"
    elif
      ! source "$rvm_scripts_path/base"
    then
      printf "%b" "WARNING:
      Errors sourcing '$rvm_scripts_path/base'.
      RVM will likely not work as expected.\n"
    else
      __rvm_ensure_is_a_function
      __rvm_setup

      export rvm_version
      rvm_version="$(\command \cat "$rvm_path/VERSION") ($(\command \cat "$rvm_path/RELEASE" 2>/dev/null))"

      alias rvm-restart="rvm_reload_flag=1 source '${rvm_scripts_path:-${rvm_path}/scripts}/rvm'"

      # Try to load RVM ruby if none loaded yet
      __path_to_ruby="$( builtin command -v ruby 2>/dev/null || true )"
      if
        [[ -z "${__path_to_ruby}" ]] ||
        [[ "${__path_to_ruby}" != "${rvm_path}"* ]] ||
        [[ "${__path_to_ruby}" == "${rvm_path}/bin/ruby" ]]
      then
        if
          [[ -n "${rvm_environments_path:-}" &&
            -s "${rvm_environments_path}/default"
          ]]
        then
          source "${rvm_environments_path}/default"
        elif
          [[ "${rvm_environments_path:-}" != "${rvm_path}/environments" &&
            -s "${rvm_path}/environments/default"
          ]]
        then
          source "${rvm_path}/environments/default"
        fi
        if
          [[ ${rvm_project_rvmrc:-1} -gt 0 ]] &&
          ! __function_on_stack __rvm_project_rvmrc
        then
          # Reload the rvmrc, use promptless ensuring shell processes does not
          # prompt if .rvmrc trust value is not stored, revert to default on fail
          if
            rvm_current_rvmrc=""
            rvm_project_rvmrc_default=2 rvm_promptless=1 __rvm_project_rvmrc
          then
            rvm_hook=after_cd
            source "${rvm_scripts_path:-${rvm_path}/scripts}/hook"
          fi
        fi
      elif
        [[ "${__path_to_ruby}" == "${rvm_path}"* ]] &&
        [[ -z "${GEM_HOME:-}" || -z "${GEM_PATH:-}" ]]
      then
        echo "
Warning: PATH set to RVM ruby but GEM_HOME and/or GEM_PATH not set, see:
    https://github.com/wayneeseguin/rvm/issues/3212
" >&2
        if
          [[ -n "${SUDO_USER:-}" ]]
        then
          echo "Hint: To fix PATH errors try using 'rvmsudo' instead of 'sudo', see:
    http://stackoverflow.com/questions/27784961/received-warning-message-path-set-to-rvm-after-updating-ruby-version-using-rvm/28080063#28080063
" >&2
        fi
      fi
      unset __path_to_ruby

      # Makes sure rvm_bin_path is in PATH atleast once.
      [[ ":${PATH}:" == *":${rvm_bin_path}:"* ]] || PATH="$PATH:${rvm_bin_path}"

      if
        (( ${rvm_reload_flag:=0} == 1 ))
      then
        [[ "${rvm_auto_reload_flag:-0}" == 2 ]] || printf "%b" 'RVM reloaded!\n'
        unset __rvm_project_rvmrc_lock
      fi

      rvm_loaded_flag=1
      __rvm_teardown

      # Opt-in for custom prompt through by setting:
      #     rvm_ps1=1
      # in either /etc/rvmrc or $HOME/.rvmrc
      if
        [[ ${rvm_ps1:-0} -eq 1 ]]
      then
        # Source RVM ps1 functions for a great prompt.
        if
          [[ -s "$rvm_path/contrib/ps1_functions" ]]
        then
          source "$rvm_path/contrib/ps1_functions"
        elif
          [[ -s "/usr/local/rvm/contrib/ps1_functions" ]]
        then
          source "/usr/local/rvm/contrib/ps1_functions"
        fi

        if command -v ps1_set >/dev/null 2>&1
        then ps1_set
        fi
      fi

    fi
  else
    printf "%b" "\n\$rvm_path ($rvm_path) does not exist."
  fi
  unset rvm_prefix_needs_trailing_slash rvm_gems_cache_path rvm_gems_path rvm_project_rvmrc_default rvm_gemset_separator rvm_reload_flag
fi
Housni
  • 963
  • 1
  • 10
  • 23

1 Answers1

3

Running a script as . ~/.rvm/scripts/rvm does not use its shebang line. It sources the script into the current shell. The current shell for passthru would seem to be /bin/sh (which is reasonable most things default to using /bin/sh).

If you want the script's shebang to be used then you need to leave off the sourcing ./source command.

Etan Reisner
  • 77,877
  • 8
  • 106
  • 148
  • So you're saying I should just do `passthru('~/.rvm/scripts/rvm');` without the [dot] or `source`? That makes sense what you said about `/bin/sh` being used because `/bin/sh` points to `dash` on my system. – Housni May 08 '15 at 13:14
  • Also, doesn't the fact that the shebang line of `~/.rvm/scripts/rvm` uses `#!/usr/bin/env bash` make that script use `bash` instead of `/bin/sh`? – Housni May 08 '15 at 13:16
  • 1
    Yes, use the path directly. As I said the shebang line is *not* used for sourced scripts. The shebang lines is used **only** for scripts that are run directly (if you ran `/bin/sh ~/.rvm/scripts/rvm` it wouldn't use the shebang line either). – Etan Reisner May 08 '15 at 13:24
  • Hmm, it doesn't seem like this solves the problem. Once I run `passthru('~/.rvm/scripts/rvm');` and then run `exec('type rvm | head -n 1');` I don't see the expected output. However, if jumped back into my terminal and ran `source ~/.rvm/scripts/rvm` and then run `type rvm | head -n 1` in the same terminal, I get the expected output. – Housni May 08 '15 at 13:48
  • 1
    I wondered if that question was coming next. Each call to `passthru`/`exec`/etc. is a separate **new** shell session. Variables/etc. do not carry from one to the next. Additionally, when running a script via path (as opposed to sourcing it) it runs in its own shell session as well. – Etan Reisner May 08 '15 at 13:55
  • I already know about that though. Even tried `passthru('~/.rvm/scripts/rvm && type rvm | head -n 1');` but to no avail. All I get is `rvm: not found`. Am I doing that wrong? – Housni May 08 '15 at 13:57
  • 1
    Yes, that was my second point. To have `~/.rvm/scripts/rvm` affect the current shell session you need the `.`/`source` approach. Which means you need to manually run `bash`. (e.g. `passthru("/bin/bash -c '. ~/.rvm/scripts/rvm && type rvm | head -n 1'")` or similar.) – Etan Reisner May 08 '15 at 13:59
  • Very cool. Thanks for waiting for me to try things out and then explaining it to me. Certainly makes more sense now that I've done it this way. – Housni May 08 '15 at 14:02