RetroPie forum home
    • Recent
    • Tags
    • Popular
    • Home
    • Docs
    • Register
    • Login

    [SCRIPT] RetroPie Shell Script Boilerplate

    Scheduled Pinned Locked Moved Projects and Themes
    scriptboilerplateshellretropie
    12 Posts 3 Posters 2.3k Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • hiulitH
      hiulit
      last edited by hiulit

      I'm starting to like creating scripts for RetroPie so I created a RetroPie Shell Script Boilerplate for myself and now I'd like to present it to you and get some feedback.

      Basically, it's a starting point with:

      • Some variables and functions that I found myself using in every script I created.
      • A config file, because I use it quite often.
      • It also includes a README.md and a CHANGELOG.md to document the script.
      • Some stuff for GitHub: a LICENSE and a CONTRIBUTING.md.

      There a lot of comments and examples on how to use the functions and how to write the documentation.
      Everything that's encapsulated in [] is editable and the comments that should be removed when the script is in 'production' are marked.

      UPDATE 1:

      • Merged #2 from @meleu .
      • Added check_dependencies().
      • Added reset_config() to use it in conjunction with set_config() and get_config().
      • Added --version (because I think everyone should use it :P)
      • Added 2 ways to find /home.
      • Added more useful global variables.

      Well, here it is:

      #!/usr/bin/env bash
      # [SCRIPT_NAME] (e.g.: script_template.sh)
      #
      # [SCRIPT_TITLE] (e.g.: RetroPie Shell Script Boilerplate)
      # [SCRIPT_DESCRIPTION] (e.g. A template for building shell scripts for RetroPie.)
      #
      # Author: [AUTHOR] (e.g. hiulit)
      # Repository: [REPO_URL] (e.g. https://github.com/hiulit/RetroPie-Shell-Script-Boilerplate)
      # License: [LICENSE] [LICENSE_URL] (e.g. MIT https://github.com/hiulit/RetroPie-Shell-Script-Boilerplate/blob/master/LICENSE)
      #
      # Requirements:
      # - RetroPie x.x.x (e.g. RetroPie 4.x.x)
      # - [PACKAGE_NAME] (e.g. libav-tools)
      
      # Globals ####################################################################
      
      # If the script is called via sudo, detect the user who called it and the homedir.
      user="$SUDO_USER"
      [[ -z "$user" ]] && user="$(id -un)"
      
      home="$(eval echo ~$user)"
      # If you really need that the script is run by root user (e.g. script called
      # from '/etc/rc.local') the approach below can work better to get the homedir
      # of the RetroPie user.
      # Comment the code above and uncomment the code below.
      #home="$(find /home -type d -name RetroPie -print -quit 2>/dev/null)"
      #home="${home%/RetroPie}"
      
      readonly RP_DIR="$home/RetroPie"
      readonly RP_CONFIG_DIR="/opt/retropie/configs"
      
      readonly SCRIPT_VERSION="0.0.0" # Use Semantinc Versioning https://semver.org/
      readonly SCRIPT_DIR="$(cd "$(dirname $0)" && pwd)"
      readonly SCRIPT_NAME="$(basename "$0")"
      readonly SCRIPT_FULL="$SCRIPT_DIR/$SCRIPT_NAME"
      #readonly SCRIPT_CFG="$SCRIPT_DIR/[CONFIG_FILE]" # Uncomment if you want/need to use a config file.
      readonly SCRIPT_TITLE="[SCRIPT_TITLE]"
      readonly SCRIPT_DESCRIPTION="[SCRIPT_DESCRIPTION]"
      #readonly SCRIPTMODULE_DIR="/opt/retropie/supplementary/[SCRIPTMODULE_NAME]" # Uncomment if you want/need to use a scriptmoodule.
      
      # Other variables that can be useful.
      #readonly DEPENDENCIES=("[PACKAGE_1]" "[PACKAGE_2]" "[PACKAGE_N]")
      #readonly ROMS_DIR="$RP_DIR/roms"
      #readonly ES_THEMES_DIR="/etc/emulationstation/themes"
      #readonly RCLOCAL="/etc/rc.local"
      #readonly GIT_REPO_URL="[REPO_URL]"
      #readonly GIT_SCRIPT_URL="[REPO_URL]/[path/to/script].sh
      
      
      # Variables ##################################################################
      
      # Add your own variables here.
      
      
      # Functions ##################################################################
      
      function is_retropie() {
          [[ -d "$RP_DIR" && -d "$home/.emulationstation" && -d "/opt/retropie" ]]
      }
      
      
      function is_sudo() {
          [[ "$(id -u)" -eq 0 ]]
      }
      
      
      # If your script has dependencies, just use the DEPENDENCIES variable on the definitions above.
      # Otherwise, leave it as is.
      function check_dependencies() {
          local pkg
          for pkg in "${DEPENDENCIES[@]}";do
              if ! dpkg-query -W -f='${Status}' "$pkg" | grep -qwo "installed"; then
                  echo "ERROR: The '$pkg' package is not installed!" >&2
                  echo "Would you like to install it now?"
                  local options=("Yes" "No")
                  local option
                  select option in "${options[@]}"; do
                      case "$option" in
                          Yes)
                              if ! which apt-get > /dev/null; then
                                  echo "ERROR: Can't install '$pkg' automatically. Try to install it manually." >&2
                                  exit 1
                              else
                                  sudo apt-get install "$pkg"
                                  break
                              fi
                              ;;
                          No)
                              echo "ERROR: Can't launch the script if the '$pkg' package is not installed." >&2
                              exit 1
                              ;;
                          *)
                              echo "Invalid option. Choose a number between 1 and ${#options[@]}."
                              ;;
                      esac
                  done
              fi
          done
      }
      
      
      function check_argument() {
          # This method doesn't accept arguments starting with '-'.
          if [[ -z "$2" || "$2" =~ ^- ]]; then
              echo >&2
              echo "ERROR: '$1' is missing an argument." >&2
              echo >&2
              echo "Try '$0 --help' for more info." >&2
              echo >&2
              return 1
          fi
      }
      
      
      # If you are using the config file, uncomment set_config() and get_config().
      # In addition, you can also uncomment reset_config() if you need it.
      # USAGE:
      # set_config "[KEY]" "[VALUE]" - Sets the VALUE to the KEY in $SCRIPT_CFG.
      # get_config "[KEY]" - Returns the KEY's VALUE in $SCRIPT_CFG.
      # reset_config - Resets all VALUES in $SCRIPT_CFG.
      #
      # function set_config() {
      #     sed -i "s|^\($1\s*=\s*\).*|\1\"$2\"|" "$SCRIPT_CFG"
      #     echo "\"$1\" set to \"$2\"."
      # }
      #
      #
      # function get_config() {
      #     local config
      #     config="$(grep -Po "(?<=^$1 = ).*" "$SCRIPT_CFG")"
      #     config="${config%\"}"
      #     config="${config#\"}"
      #     echo "$config"
      # }
      #
      #
      # function reset_config() {
      #     while read line; do
      #         set_config "$line" ""
      #     done < <(grep -Po ".*?(?=\ = )" "$SCRIPT_CFG")
      # }
      
      
      function usage() {
          echo
          echo "USAGE: $0 [OPTIONS]" # Add 'sudo' before '$0' if the script needs to be run under sudo (e.g. USAGE: sudo $0 [OPTIONS]). Don't change [OPTIONS]! Remember to remove this comment.
          echo
          echo "Use '$0 --help' to see all the options." # Add 'sudo' before '$0' if the script needs to be run under sudo (e.g. Use 'sudo $0 --help' ...). Remember to remove this comment.
      }
      
      # Add your own functions here.
      
      # You can add as many options as you want.
      # To add a new option -> Copy and paste from '#H -[O], --[OPTION] ...' until ';;' and make the desired changes.
      # If you want to align the descriptions of the options, just play with adding/removing spaces/tabs :P
      function get_options() {
          if [[ -z "$1" ]]; then
              usage
              exit 0
          else
              case "$1" in
      #H -h, --help                   Print the help message and exit.
                  -h|--help)
                      echo
                      echo "$SCRIPT_TITLE"
                      for ((i=1; i<="${#SCRIPT_TITLE}"; i+=1)); do [[ -n "$dashes" ]] && dashes+="-" || dashes="-"; done && echo "$dashes"
                      echo "$SCRIPT_DESCRIPTION"
                      echo
                      echo "USAGE: $0 [OPTIONS]" # Add 'sudo' before '$0' if the script needs to be run under sudo (e.g. USAGE: sudo $0 [OPTIONS]). Don't change [OPTIONS]! Remember to remove this comment.
                      echo
                      echo "OPTIONS:"
                      echo
                      sed '/^#H /!d; s/^#H //' "$0"
                      echo
                      exit 0
                      ;;
      #H -v, --version                Show script version.
                  -v|--version)
                      echo "$SCRIPT_VERSION"
                      ;;
      #H -[O], --[OPTION] (e.g '-v, --version')       [OPTION_DESCRIPTION] (e.g. Show script version.).
                  -[O]|--[OPTION])
                      # If the option has arguments, uncomment the code below.
                      # check_argument "$1" "$2" || exit 1
                      # shift
      
                      # Add the functions for this options here.
                      ;;
                  *)
                      echo "ERROR: invalid option '$1'" >&2
                      exit 2
                      ;;
              esac
          fi
      }
      
      function main() {
          # If you need to check if sudo is used, uncomment the code below.
          # Remember to add 'sudo' in 'usage' and 'help'.
          # if ! is_sudo; then
          #     echo "ERROR: Script must be run under sudo."
          #     usage
          #     exit 1
          # fi
      
          if ! is_retropie; then
              echo "ERROR: RetroPie is not installed. Aborting ..." >&2
              exit 1
          fi
      
          check_dependencies
      
          get_options "$@"
      }
      
      main "$@"
      

      and the config file:

      # Settings for [SCRIPT_TITLE] (e.g. RetroPie Shell Script Boilerplate)
      
      # Add your own [key = "value"] (e.g. path_to_whatever = "/path/to/whatever")
      # [KEY] WITHOUT quotes.
      # [VALUE] WITH quotes.
      # There MUST be 1 space before and after '='.
      # To indicate that a [KEY] has NO [VALUE] or is NOT SET, just leave the quotes, like this: "".
      
      # Description of the [key = "value"] (e.g. # Set path to whatever).
      [KEY] = "[VALUE]"
      
      # Add your own [key = "value"]
      

      I would like to especially thank @meleu for helping me with other projects I've worked on.

      I hope that somebody will find this useful and also I'd like to hear some feedback (criticism, suggestions, etc.) so I can improve it and in addition improve my skills developing scripts for RetroPie :D

      My little contributions to the RetroPie project:

      • Shell-Script-Boilerplate
      • Fun-Facts-Splashscreens
      • Limit-Last-Played-Games
      cyperghostC meleuM 2 Replies Last reply Reply Quote 4
      • cyperghostC
        cyperghost @hiulit
        last edited by

        @hiulit If I ever will use config files than this would be a good starting point ;) Usually I parse arguments via command parameters as all of my scripts are very tight and need no configuration.

        hiulitH 1 Reply Last reply Reply Quote 1
        • meleuM
          meleu @hiulit
          last edited by meleu

          @hiulit OMFG! I was thinking about making the same thing but was a bit unmotivated to start it from scratch. Now you started it... such a relief! :D

          After writing all those scripts here and there for the RetroPie community I think I have something to share. I hope to find some time to contribute on your repo.

          Thanks for bringing this up!

          • Useful topics
          • joystick-selection tool
          • rpie-art tool
          • achievements I made
          hiulitH 1 Reply Last reply Reply Quote 1
          • hiulitH
            hiulit @cyperghost
            last edited by

            @cyperghost I'm glad you like! :D
            I like to use config files because it makes the script more 'user-friendly' in my opinion. Feel free to contribute to the repo if you find a better way of handling config files (setting and getting values)

            My little contributions to the RetroPie project:

            • Shell-Script-Boilerplate
            • Fun-Facts-Splashscreens
            • Limit-Last-Played-Games
            1 Reply Last reply Reply Quote 0
            • hiulitH
              hiulit @meleu
              last edited by

              @meleu Awesome! I'm already waiting for your contributions! And any other person who'd like to contribute too.
              Together we can come up with a nice and useful boilerplate :)

              My little contributions to the RetroPie project:

              • Shell-Script-Boilerplate
              • Fun-Facts-Splashscreens
              • Limit-Last-Played-Games
              meleuM 1 Reply Last reply Reply Quote 0
              • meleuM
                meleu @hiulit
                last edited by

                @hiulit I think the comments are kinda wordy. Would you mind if I change the style, trying to reduce the text a bit?

                • Useful topics
                • joystick-selection tool
                • rpie-art tool
                • achievements I made
                hiulitH 1 Reply Last reply Reply Quote 0
                • hiulitH
                  hiulit @meleu
                  last edited by

                  @meleu Yeah, sure, no problem! Go for it!

                  My little contributions to the RetroPie project:

                  • Shell-Script-Boilerplate
                  • Fun-Facts-Splashscreens
                  • Limit-Last-Played-Games
                  meleuM 1 Reply Last reply Reply Quote 0
                  • meleuM
                    meleu @hiulit
                    last edited by

                    @hiulit PR submitted.

                    • Useful topics
                    • joystick-selection tool
                    • rpie-art tool
                    • achievements I made
                    hiulitH 1 Reply Last reply Reply Quote 0
                    • hiulitH
                      hiulit @meleu
                      last edited by

                      @meleu Thanks! PR commented ;)

                      My little contributions to the RetroPie project:

                      • Shell-Script-Boilerplate
                      • Fun-Facts-Splashscreens
                      • Limit-Last-Played-Games
                      1 Reply Last reply Reply Quote 0
                      • hiulitH
                        hiulit
                        last edited by

                        I've updated the RetroPie Shell Script Boilerplate:

                        UPDATE 1:

                        • Merged #2 from @meleu .
                        • Added check_dependencies().
                        • Added reset_config() to use it in conjunction with set_config() and get_config().
                        • Added --version (because I think everyone should use it :P)
                        • Added 2 ways to find /home.
                        • Added more useful global variables.

                        These changes are also reflected in the first comment.

                        Coming soon... dialog functions!! Again, thanks to @meleu ;)

                        My little contributions to the RetroPie project:

                        • Shell-Script-Boilerplate
                        • Fun-Facts-Splashscreens
                        • Limit-Last-Played-Games
                        cyperghostC 1 Reply Last reply Reply Quote 0
                        • cyperghostC
                          cyperghost @hiulit
                          last edited by cyperghost

                          @hiulit Some additional functions

                          # This will determine of savestate directory = config
                          # This is part of hiuilits Boilerplate script, with small modification
                          # if '~' is detected then expand full homepath
                          function get_config() {
                              local config
                              config="$(grep -Po "(?<=^$1 = ).*" "$CONFIG_FILE")"
                              config="${config%\"}"
                              config="${config#\"}"
                              # [[ ${config:0:1} = "~" ]] && config="${config#??}" && config=~/"$config" # Expand homepath
                              # [[ -z ${config##*/} ]] && config="${config%?}" # Sanitize pathes if last character is a /
                              # [[ ${config:0:1} != "/" ]] && config="annother value because it is likely no path"
                              echo "$config"
                          }
                          
                          # This will determine which script is curently running
                          # Is it 'runcommand-onend.sh' or 'runcommand-onstart.sh'
                          # It will extract 'end' or 'start' ... Usefull if you need to know which runcommand called the script
                          function get_runcommand() {
                             local i
                             local file_array=("runcommand-onend.sh" "runcommand-onstart.sh")
                             for i in "${file_array[@]}"
                             do
                                [[ $(pgrep -f "$i") ]] && i="${i#*-on}" && echo "${i%.*}"
                             done
                          }
                          
                          # Determining file ages
                          function file_age() {
                              echo "$(date +%s -r "$1")"
                          }
                          
                          hiulitH 1 Reply Last reply Reply Quote 1
                          • hiulitH
                            hiulit @cyperghost
                            last edited by

                            @cyperghost Hey, thanks! I'll take a look at them ;)

                            My little contributions to the RetroPie project:

                            • Shell-Script-Boilerplate
                            • Fun-Facts-Splashscreens
                            • Limit-Last-Played-Games
                            1 Reply Last reply Reply Quote 0
                            • First post
                              Last post

                            Contributions to the project are always appreciated, so if you would like to support us with a donation you can do so here.

                            Hosting provided by Mythic-Beasts. See the Hosting Information page for more information.