Please do not post a support request without first reading and following the advice in https://retropie.org.uk/forum/topic/3/read-this-first

shell scripting topic



  • 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?



  • @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.



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

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



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



  • @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!



  • @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 :)



  • 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
    


  • @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[@]}"
    


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



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



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.