shell scripting topic
-
@meleu Yeah, you're right. Pixel theme images look fine on my 1920x1080 monitor. I'll try it! ;)
-
I've created this little script to format all
theme.xml
from a given EmulationStation theme with 4 spaces. It's really unnecessary, but I'm that kind of person :PHere it goes:
#!/usr/bin/env bash THEME="pixel" for folder in "/etc/emulationstation/themes/$THEME/"*; do if [[ -d "$folder" ]]; then if [[ -f "$folder/theme.xml" ]]; then cp "$folder/theme.xml" "$folder/theme-backup.xml" xmlstarlet fo -s 4 "$folder/theme.xml" > "$folder/theme-indent.xml" sed -i '/\?xml/d' "$folder/theme-indent.xml" cp "$folder/theme-indent.xml" "$folder/theme.xml" rm "$folder/theme-indent.xml" "$folder/theme-backup.xml" fi fi done
-
When you have a dialog inside a dialog inside a dialog (and so on...), can the "Cancel" button act as a "Back" button? I know the label can be changed, but when you click it it goes back to the first dialog :(
-
@hiulit there's no "dialog inside a dialog". You execute a dialog and when you choose the "OK" or "Cancel" button the dialog finishes.
What causes that impression of a "dialog inside a dialog" is usually a dialog being called one right after another, each one inside its own while loop structure.
The example I have to show is one of my codes that I am least proud of when it comes to well-written code, but well, let's try...
Check the rpie-art code here: https://github.com/meleu/rpie-art/blob/master/rpie-art.sh
This while loop in
main_menu()
contains the first dialog. Depending on the option, the script calls another function which has another dialog. Let's follow theuninstall_art_menu()
flow.When the user choose X on the
main_menu()
, the script calls theuninstall_art_menu()
function which has another dialog where you can:- Choose Cancel: the logic flow returns to
main_menu()
and that loop calls themain_menu()
's dialog again. - Choose a valid option. Which calls another function which has another dialog and the chain-of-dialogs goes on...
Eh... I'm not sure if I explained well. 😅
Read, check the code and reread. If you still don't understand feel free to ask. ;-)
- Choose Cancel: the logic flow returns to
-
@meleu Thanks! That's what I thought. I'll create some functions then, as you did ;)
-
Hi there!
Can somebody help me figure this out?I have an argument passed to a shell script
fun-facts-splashscreens.sh --create-fun-fact
that can have:- no options
- 1 option [system]
- 2 options [system rom]
How can I write a help message?
--create -fun-fact [] [system] [system rom]
?Thanks!
-
@hiulit Add a -h option and display the help when this option is passed to the script.
-
@mitu I'm sorry, I didn't explain myself clearly enough.
I already have a
-h
option that shows all the options available. What I meant is, how should I tell the user that the option--create-fun-fact
can have:- no options
- 1 option [system]
- 2 options [system rom]
That's what I've come up with:
--create-fun-fact [] [system] [system rom]
Is that correct?Did I explain myself better this time? :P
-
@hiulit said in shell scripting topic:
--create-fun-fact [] [system] [system rom]
Ah, ok. I think the correct syntax would be
--create-fun-fact [SYSTEM] [ROM]
Usually an argument in brackets (
[arg]
) means the argument is optional. -
@mitu I see! And if an argument is NOT optional? I have some of those around :P
-
@hiulit If it's not optional, just remove the brackets.
--create-fun-fact system [rom]
-
@hiulit can you explain the use case and provide some examples?
I'm sure we can find ways to make an option have zero, one or two options, but from a user point of view I think it's a bit confusing.
EDIT:
I can't see what would be the use for--create-fun-fact system rom
, but if it's intended to be used on RetroPie, you can detect the system by looking the directory where the rom is located. -
@meleu I'll try to explain myself even better than the last time :P Here we go!
This all comes from the
fun-facts-splashscreens-runcommand-onend.sh
that has these lines:SYSTEM="$1" ROM_PATH="$3" sudo "$SCRIPT_DIR/fun-facts-splashscreens.sh" --create-fun-fact "$SYSTEM" "ROM_PATH"
This is what creates the launching images when stoping the game. This is something the user doesn't need to care about. But then I already had
--create-fun-fact
in the help message so I wanted to let the user use it, like this:--create-fun-fact
with no options passed creates a boot splashscreen.--create-fun-fact [SYSTEM]
(SYSTEM can beall
or any RetroPie system) creates launching images for all the systems, or the given system with the system's logo (and console if it exists).--create-fun-fact [SYSTEM] [ROM]
(ROM can be an absolute path or just the ROM's name + ext, and then it takes the given system to look for the path) creates a launching image for the game.
Examples:
--create-fun-fact
--create-fun-fact
all--create-fun-fact
megadrive--create-fun-fact
megadrive "/home/RetroPie/megadrive/Sonic the Hedgehog.zip"--create-fun-fact
megadrive "Sonic the Hedgehog.zip"
I can see that from the user's perspective it could be a little confusing... Maybe it's better to split
--create-fun-fact
into two separate functions--create-fun-fact-boot-splashscreen
and--create-fun-fact-launching-images
.Maybe I should remove this option from the help message? Just have it for myself to test?
That's something that can be done via the GUI, btw: -
@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!
-
@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 ;) -
I've just found this and decided to share here:
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. -
@meleu Wow this is really helpfull ;) Cool snippets for bash coders. Thank you so much.
For ex:
Reverse array I didfor ((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 ....
-
@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
-
@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
-
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
returns08
, and when I try to compare it, bash doesn't see08
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 the10#
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 the10#
operand.Any thoughts on where to get info about it?
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.