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

    shell scripting topic

    Scheduled Pinned Locked Moved Ideas and Development
    shellshell scriptprogramming
    191 Posts 10 Posters 86.2k 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.
    • meleuM
      meleu @hiulit
      last edited by

      @hiulit You wouldn't want to create a launching image for Sonic using a NES splashscreen, would you? Well, my suggestion below does not have this kind of flexibility, but here it go:

      help message

      --create-fun-fact [system|path/to/a/ROM]     no arguments = create boot splashscreen
                                                   system = create a launching image for system
                                                   ROM = create a launching image for a ROM
      

      If you wanna use this approach, please write a better help message for this option! ;)

      code

      #!/bin/bash
      
      user="$SUDO_USER"
      [[ -z "$user" ]] && user="$(id -un)"
      home="$(eval echo ~$user)"
      
      readonly RP_DIR="$home/RetroPie"
      readonly RP_ROMS_DIR="$RP_DIR/roms"
      readonly RP_CONFIG_DIR="/opt/retropie/configs"
      
      function get_options() {
      
          case "$1" in
      
      #H --create-fun-fact [system|path/to/a/ROM]     no arguments = create boot splashscreen
      #H                                              system = create a launching image for system
      #H                                              ROM = create a launching image for a ROM
              --create-fun-fact)
                  if [[ -z "$2" ]]; then
                      # NOTE: for this usecase the --create-fun-fact MUST be the
                      #       last parameter used in the command line.
                      echo "Let's create a boot splashscreen with a fun fact!"
      
                  elif [[ -f "$2" ]]; then
                      # NOTE: if it's a regular file, let's check if it's a ROM and
                      #       create a splashscreen for this game.
                      local rom_full_path="$(realpath "$2")"
      
                      if [[ "$rom_full_path" != "$RP_ROMS_DIR"* ]]; then
                          echo "ERROR: \"$2\" is not on a valid ROM directory" >&2
                          exit 1
                      fi
      
                      # Reference for the tricks used to get the system's name below:
                      # http://www.tldp.org/LDP/abs/html/parameter-substitution.html#PSOREX2
                      system="${rom_full_path#$RP_ROMS_DIR/}"
                      system="${system%/*}"
      
                      echo "Let's create a launching image for \"$2\" using the ${system}'s one!"
      
                  elif [[ -d "$RP_CONFIG_DIR/$2" ]]; then
                      echo "Let's create a launching image for \"$2\" system!"
      
                  else
                      echo "ERROR: \"$2\": invalid argument." >&2
                      exit 1
                  fi
                  ;;
      
      #H --help                                       Print the help message and exit.
              --help|-h)
                  sed '/^#H /!d; s/^#H //' "$0"
                  echo
                  exit 0
                  ;;
          esac
      }
      
      get_options "$@"
      

      testing

      $ ./cff.sh --create-fun-fact
      Let's create a boot splashscreen with a fun fact!
      
      $ ./cff.sh --create-fun-fact abcd
      ERROR: "abcd": invalid argument.
      
      $ ./cff.sh --create-fun-fact nes
      Let's create a launching image for "nes" system!
      
      $ ./cff.sh --create-fun-fact ~/RetroPie/roms/nes
      ERROR: "/home/meleu/RetroPie/roms/nes": invalid argument.
      
      $ ./cff.sh --create-fun-fact ~/RetroPie/roms/nes/Contra\ \(USA\).zip 
      Let's create a launching image for "/home/meleu/RetroPie/roms/nes/Contra (USA).zip" using the nes's one!
      
      • 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 hiulit

        @meleu Thanks for your reply! And no, I wouldn't want that

        launching image for Sonic using a NES splashscreen
        But my script prevents from doing that.

        I'll try to paste every piece of code that I have, because it's very similar to what you have:

        -cff|--create-fun-fact)
            is_fun_facts_empty
            if [[ -z "$2" ]]; then
                create_fun_fact
            else
                shift
                create_fun_fact "$@"
                shift
            fi
            ;;
        

        If no arguments are passed called create_fun_fact without arguments, if there are any arguments, pass them all.

        function create_fun_fact() {
            if [[ -z "$1" ]]; then
                create_fun_fact_boot
            else
                create_fun_fact_launching "$@"
            fi
        }
        

        There's more things going one here, but it basically calls one function or another depending on if there are arguments.
        create_fun_fact_boot is self explanatory.
        create_funfact_launching takes all the arguments and then:

        function create_fun_fact_launching() {
            local system="$1"
            local rom_path="$2"
        
            if [[ "$system" == "all" ]]; then
                // Loop all systems and call create_fun_fact_launching "$system"
            else
                if [[ -n "$rom_path" ]]; then
                    // Check if $system it's the same in "rom_path"
                    if true
                        // Create launching image for the game
                    else
                        // Create launching image for the system
                else
                    // Create launching image for the system
                fi
            fi
        }
        

        More or less that what I do. I think it's similar of what you wrote.

        But then again, I think maybe it's better to to have 2 separate options:

        • --create-fun-facts-boot-splashscreen(doesn't accept any argument)
        • --create-fun-facts-launching-images (accepts system and rom)

        EDIT:
        You can take a look for youself https://github.com/hiulit/RetroPie-Fun-Facts-Splashscreens/blob/new-gui-menu/fun-facts-splashscreens.sh ;)

        My little contributions to the RetroPie project:

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

          I've just found this and decided to share here:

          Pure Bash Bible

          The goal of this book is to document known and unknown methods of doing various tasks using only built-in bash features. Using the snippets from this bible can help remove unneeded dependencies from scripts and in most cases make them faster.

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

            @meleu Wow this is really helpfull ;) Cool snippets for bash coders. Thank you so much.

            For ex:
            Reverse array I did

            for ((z=${#array[*]}-1; z>-1; z--)); do
                   echo "${array[z]}"
            done
            

            Reverse array with the bash-bible

            ## Reverse an array
            
            # ```sh
            reverse_array() {
                # Usage: reverse_array "array"
                shopt -s extdebug
                f()(printf '%s\n' "${BASH_ARGV[@]}"); f "$@"
                shopt -u extdebug
            }
            # ```
            

            Up to now my version seems a bit less complex. Maybe it's due my limited coding skills. I'm still learning ....

            1 Reply Last reply Reply Quote 0
            • cyperghostC
              cyperghost
              last edited by cyperghost

              @meleu I think that's just a note to me ... BashPitfalls

              function1(){
                  local status=$(false)
                  echo $?
              }
              

              Will return 0 which is obviously wrong
              So the return code 0 just indicates the correct setting of a local setted value, which was correctly done ;)

              So to get out of this make following

              function1(){
                  local status
                  status=$(false)
                  echo $?
              }
              

              This will put out correct value for "error" 1

              That's all folks

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

                @cyperghost yeah, that's a thing to be careful. I learned it while reading the RetroPie's Shell Style Guide: https://retropie.org.uk/docs/Shell-Style-Guide/#use-local-variables

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

                  I would like to share a little trick I learned today and also ask for some help...

                  First the short story

                  I was needing to check if the current hour is after 18h, then I tried this:

                  hour=$(date +%H)
                  if [[ $hour -gt 18 ]]; then
                      echo "do something..."
                  fi
                  

                  And then I got this error (please, forgive the non-english):

                  -bash: [[: 08: valor muito grande para esta base de numeração (token de erro é "08")
                  

                  As you can see, the problem is that date +%H returns 08, and when I try to compare it, bash doesn't see 08 as a decimal number.

                  The solution is obviously getting rid of that leading zero. I decided that using sed would be overkill for such a simple task, then I've found a pure bash solution using a feature of $(( )).

                  hour=$(date +%H)
                  hour=$(( 10#$hour ))  # could also be an oneliner: $(( 10#$(date +%H) ))
                  if [[ $hour -gt 18 ]]; then
                      echo "do something..."
                  fi
                  

                  And now my script is working perfectly!

                  Now the help I mentioned earlier on the beginning of this post...

                  On that stackoverflow answer I see this:

                  The $(( )) sets up an arithmetic context and the 10# converts the number from base 10 to base 10 causing any leading zeros to be dropped.

                  Alright, but I like to see stuff on the official documentation in a hope to learn more tricks. The $(( )) is a bash builtin feature, but in the official documentation there's no mention to the 10# operand.

                  Any thoughts on where to get info about it?

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

                    @meleu That I can answer !
                    Actually it's in the very doc you mention :
                    https://www.gnu.org/software/bash/manual/bash.html#Shell-Arithmetic

                    Constants with a leading 0 are interpreted as octal numbers. A leading ‘0x’ or ‘0X’ denotes hexadecimal. Otherwise, numbers take the form [base#]n, where the optional base is a decimal number between 2 and 64 representing the arithmetic base, and n is a number in that base. If base# is omitted, then base 10 is used. When specifying n, the digits greater than 9 are represented by the lowercase letters, the uppercase letters, ‘@’, and ‘_’, in that order. If base is less than or equal to 36, lowercase and uppercase letters may be used interchangeably to represent numbers between 10 and 35.

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

                      @sano whoops! Didn't catch those little words 😅

                      Thanks Sano-san. And yeah, I learned more tricks!

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

                        @meleu Just FYI, you could just have used date +%-H ;)
                        Glad to see you here again BTW !

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

                          @sano ouch! Looks like I need RTFM some more...

                          From the date man page:

                                 By default, date  pads  numeric  fields  with  zeroes.   The  following
                                 optional flags may follow '%':
                          
                                 -      (hyphen) do not pad the field
                          

                          Thanks again, Sanso-sensei!

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

                            @meleu I really deserve no special credit for this, I just remembered something like this existed, probably had to use it in the past, too :)

                            1 Reply Last reply Reply Quote 0
                            • cyperghostC
                              cyperghost
                              last edited by cyperghost

                              A common mistake is often made by using grep.
                              It is often told that grep finds a total of all search strings within a text file due the -c switch. That is total nonsense .... -c just counts lines

                              So we miss

                              hello hello hello hello
                              hello
                              
                              grep -c hello
                              2
                              

                              We use a small hack ;)
                              Better is to use the -o option is will show occourences of search string listed in newline and now we pipe to wc -l ... and count lines again - now we catched them all ;)

                              hello hello hello hello
                              hello
                              
                              grep -o hello | wc -l
                              5
                              
                              1 Reply Last reply Reply Quote 0
                              • cyperghostC
                                cyperghost
                                last edited by cyperghost

                                @meleu

                                EDIT BEGIN
                                I think I found a good solution with pure bash
                                But maybe some knows a better one ;)

                                val=${#Unix[@]}
                                for ((i=0; i<$val; i+=1)); do
                                

                                EDIT END


                                Is there something that can be made easier (more efficient) than this script?
                                I want to merge two arrys
                                A1=(1 2 3)
                                A2=(one two there)
                                the result should be A3
                                A3=(1 one 2 two 3 three)

                                It works with this script.
                                But first... I want to avoid any counters (if possible)
                                Do you know a nice trick to count up values {0..6} works only with fixed characters not as variable. So {0..6} is fine {0..$arraysize} not

                                #!/bin/bash
                                # A small script to show how to merge two arrays
                                # with alternating values (exp. for creating arrays for dialogs)
                                
                                # Example Array
                                Unix=("Debian" "Red hat" "Ubuntu" "Suse" "Fedora" "UTS" "OpenLinux")
                                Shell=("bash" "csh" "jsh" "rsh" "ksh" "rc" "tcsh")
                                
                                # Check if both arrays got some size
                                [[ ${#Unix[@]} -eq ${#Shell[@]} ]] || exit 1
                                echo "Both arrays got same size -- Proceed"
                                
                                val=$((${#Unix[@]}-1))
                                echo $val
                                for i in $(seq 0 $val); do
                                    echo "Merging ${Unix[$i]} and ${Shell[$i]}"
                                    UnixShell+=("${Unix[$i]}" "${Shell[$i]}")
                                done
                                
                                echo "${UnixShell[@]}"
                                
                                meleuM 1 Reply Last reply Reply Quote 0
                                • meleuM
                                  meleu @cyperghost
                                  last edited by

                                  @cyperghost both methods are perfectly valid (using a for to iterate through all items).

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

                                    @meleu thanks for the feedback -- I appreciate it ;)
                                    Come on ... take a look in the MAME RoW now - if you have time ;)

                                    1 Reply Last reply Reply Quote 0
                                    • hiulitH
                                      hiulit
                                      last edited by

                                      FYI, I'll release a new version of RetroPie Shell Script Boilerplate soon-ish.

                                      This is a template for building shell scripts for RetroPie, with some helper functions, dialogs, etc.

                                      My little contributions to the RetroPie project:

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

                                        Well, here it is! A new version of RetroPie Shell Script Boilerplate.

                                        This is a template for building shell scripts for RetroPie.

                                        I've added examples of the following dialog boxes:

                                        • --infobox
                                        • --yesno
                                        • --msgbox
                                        • --menu

                                        All the dialogs can be found at utils/dialogs.sh

                                        I've also moved some functions to utils/base.sh.

                                        My little contributions to the RetroPie project:

                                        • Shell-Script-Boilerplate
                                        • Fun-Facts-Splashscreens
                                        • Limit-Last-Played-Games
                                        1 Reply Last reply Reply Quote 1
                                        • 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.