Showing posts with label Bash Script. Show all posts
Showing posts with label Bash Script. Show all posts

Wednesday, 8 June 2016

Integer Arrays in Bash

For reference I am on Ubuntu 15.10. This is something again I really struggled with hence thought it best to document

If you are one of those trying to use an Integer Array in a bash script, for example if your trying to identify how many days in a month for a particular year you might want to store in 2 integer arrays, one for a leap year and the other for a normal year. In my case I was trying to find the day of the year from the date provided.

Again what I found out there was a comma separated values, hence my array looked like this

  DAYS_IN_MONTHS=( 31,28,31,30,31,30,31,31,30,31,30,31 )
  DAYS_IN_MONTHS_LEAP_YEAR=( 31,29,31,30,31,30,31,31,30,31,30,31 )

But when I kept looping through the array as below, it still didn't work

  for((i=0;i<limit;i++))
    do
      if [ $[$year % 400] -eq 0 ]; then
        current=${DAYS_IN_MONTHS_LEAP_YEAR[$i]}
      elif [ $[$year % 4] -eq 0 ]; then
        if [ $[$year % 100] -ne 0 ]; then
          current=${DAYS_IN_MONTHS_LEAP_YEAR[$i]}
        else
          current=${DAYS_IN_MONTHS[$i]}
        fi
      else
        current=${DAYS_IN_MONTHS[$i]}
      fi
   dayOfYear=$((dayOfYear+current))
  done

When I did an echo on DAYS_IN_MONTHS[$i] within the loop it seemed to be displaying the entire array as the first element.

Totally confused as to why it wasn't working, am sure all of you know about how important spaces are in bash, I finally figured it was a space issue.

When I changed the arrays into the below, I was now getting individual elements but except the last element, everything had a comma(',') suffixed. 

  DAYS_IN_MONTHS=( 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 )
  DAYS_IN_MONTHS_LEAP_YEAR=( 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 )

So the next logical step was to remove the ',' from each element as below and that made it work.

  DAYS_IN_MONTHS=( 31 28 31 30 31 30 31 31 30 31 30 31)
  DAYS_IN_MONTHS_LEAP_YEAR=( 31 29 31 30 31 30 31 31 30 31 30 31)

Hope that helps someone?

Sunday, 5 June 2016

key=value: command not found

For reference I am on Ubuntu 15.10.

When you use the source on command line have you ever encountered key=value: command not found this error? Or even in a bash script?

$ source <filename>
key=value: command not found

Most of the information on the Ubuntu website takes you in the direction of executing this command in the wrong shell. I was running a bash script with the above command throwing the above error. So according to what I found the first line of your bash script should have been #!/bin/bash and not #!/bin/sh which is exactly what I had.

I then ran the same command on the bash shell and got exactly the same error. Now that I knew this was not my shell, I had to figure out what the cause was.

Also instead of running a source <filename> you can apparently do a . <filename> and this also resulted in exactly the same error.

'source' apparently is supposed to be the long version of '.' command. On the bash prompt one can do:

$ source ~/.bashrc

or


$ . ~/.bashrc

It took me hours of debugging to finally figure out what I was doing wrong, and hence why I decided to document it hoping it might be useful to someone out there.

You need to understand what a source does before you can debug the issue. The problem with source is, its a shell built-in which means that there's no documentation available for it through man. On a terminal type the below:

$ man source
No manual entry for source

Now try the below
$ type source
source is a shell builtin


And when you try source on its own
$ source
bash: source: filename argument required
source: usage: source filename [arguments]

Right, so how do I get more information on source and what does a source actually do?

Since I was in bash, and source is a shell builtin the next thing is to do a man bash, and search for a source in the manual.

 $ man bash
       source filename [arguments]
              Read and execute commands from filename  in  the  current  shell
              environment  and return the exit status of the last command exe‐
              cuted from filename.  If filename  does  not  contain  a  slash,
              filenames  in  PATH  are  used  to find the directory containing
              filename.  The file searched for in PATH need not be executable.
              When  bash  is  not  in  posix  mode,  the  current directory is
              searched if no file is found in PATH.  If the sourcepath  option
              to  the  shopt  builtin  command  is turned off, the PATH is not
              searched.  If any arguments are supplied, they become the  posi‐
              tional  parameters  when  filename  is  executed.  Otherwise the
              positional parameters are unchanged.  The return status  is  the
              status  of  the  last  command exited within the script (0 if no
              commands are executed), and false if filename is  not  found  or
              cannot be read.


Or as quoted from http://superuser.com/questions/46139/what-does-source-do

"info source

BASH BUILTIN COMMANDS
       Unless otherwise noted, each builtin command documented in this section
       as accepting options preceded by - accepts -- to signify the end of the
       options.   The  :, true, false, and test builtins do not accept options
       and do not treat -- specially.  The exit, logout, break, continue, let,
       and  shift builtins accept and process arguments beginning with - with-
       out requiring --.  Other builtins that accept  arguments  but  are  not
       specified  as accepting options interpret arguments beginning with - as
       invalid options and require -- to prevent this interpretation.
       : [arguments]
              No effect; the command does nothing beyond  expanding  arguments
              and  performing any specified redirections.  A zero exit code is
              returned.

        .  filename [arguments]
       source filename [arguments]
              Read and execute commands from filename  in  the  current  shell
              environment  and return the exit status of the last command exe-
              cuted from filename.  If filename does not contain a slash, file
              names  in  PATH  are used to find the directory containing file-
              name.  The file searched for in PATH  need  not  be  executable.
              When  bash  is  not  in  posix  mode,  the  current directory is
              searched if no file is found in PATH.  If the sourcepath  option
              to  the  shopt  builtin  command  is turned off, the PATH is not
              searched.  If any arguments are supplied, they become the  posi-
              tional  parameters  when  filename  is  executed.  Otherwise the
              positional parameters are unchanged.  The return status  is  the
              status  of  the  last  command exited within the script (0 if no
              commands are executed), and false if filename is  not  found  or
              cannot be read."


Also quoting from stackoverflow "@robinst: Sourcing the file using . or source has the problem that you can also put commands in there that are executed. If the input is not absolutely trusted, that's a problem (hello rm -rf /)."

And that told me what the problem was. In the end what it was is that if your key contains a hyphen '-' instead of an underscore '_' then you would encounter this error. Obviously my key had a hyphen which was getting converted into a command probably with a corresponding parameter

If you want to try this, do the following:
$ vi ~/test
and enter the below
key-1=value1
and save the file

Now try the following in your terminal
source ~/test
and you would see the error below
key-1=value1: command not found