LinuxQuestions.org
Download your favorite Linux distribution at LQ ISO.
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie
User Name
Password
Linux - Newbie This Linux forum is for members that are new to Linux.
Just starting out and have a question? If it is not in the man pages or the how-to's this is the place!

Notices

Reply
 
Search this Thread
Old 04-03-2012, 07:51 AM   #1
Mark1986
Member
 
Registered: Aug 2008
Location: Netherlands
Distribution: Xubuntu
Posts: 87

Rep: Reputation: 11
Unexpected output getopts in AIX


Hi all,

Currently I am using AIX at work. I am no administrator of the system, merely a user.

I am trying to create a script that will accept either a file with a list of files as content, or a list of files. At first I build it for myself, but I want it to be available for my colleagues in the longer run.

The script is called mailen (Dutch for mailing). Either you start the script as: ./mailen file1 file2 file3 or as: ./mailen -f file_list file1 file2

In the first case, it should e-mail the files (file1, file2 and file3) to me as an attachment. In the second case, it should read the content of the file file_list and e-mail me the files in the content from that list and file1 and file2.

So I started with a script that would e-mail me the files I put on the command line. The script works as designed.

The next step is to try and see if I can make a script that will get the content of the file in case I use the -f (file) option.

The script I have should contain 2 options, namely -v (verbose) and -f (file to read content from).

This is what I have so far:

Code:
#!/bin/bash
#

V_FLAG=
F_FLAG=
FILE=

while getopts vf: opt
do
  case $opt in
  v)
    V_FLAG=1
  ;;
  f)
    F_FLAG=1
    FILE="$OPTARG"
  ;;
  \?)
    echo ""
    echo "Usage of mailen:"
    echo "$0 [-v] [-f filename] [file ...]"
    echo ""
    exit 1
  ;;
  esac
done

shift $((OPTIND - 1))

echo "Rest $@"
echo ""
echo "V_FLAG=${V_FLAG}"
echo "F_FLAG=${F_FLAG}"
echo "FILE=${FILE}"

exit 0
Now running it:

$ ./mailen_getopts.sh -f foo foo1 foo2
Rest foo1 foo2

V_FLAG=
F_FLAG=1
FILE=foo

$ ./mailen_getopts.sh -f foo -v foo1 foo2
Rest foo1 foo2

V_FLAG=1
F_FLAG=1
FILE=foo

$ ./mailen_getopts.sh -v foo -f foo1 foo2
Rest foo -f foo1 foo2

V_FLAG=1
F_FLAG=
FILE=

As you can see, in the first 2 cases output is as expected. However in the last case, -f seems not to be an option anymore... For some reason if you tell getopts that an option should not have an argument, it will not parse the rest of the string if you don't provide a new option right away.

Has anyone encountered this before? Does anyone know how to overcome this without loosing too much flexibility?
 
Old 04-03-2012, 09:06 AM   #2
catkin
LQ 5k Club
 
Registered: Dec 2008
Location: Tamil Nadu, India
Distribution: Servers: Debian Squeeze and Wheezy. Desktop: Slackware64 14.0. Netbook: Slackware 13.37
Posts: 8,563
Blog Entries: 29

Rep: Reputation: 1179Reputation: 1179Reputation: 1179Reputation: 1179Reputation: 1179Reputation: 1179Reputation: 1179Reputation: 1179Reputation: 1179
That's normal behaviour.

When getopts finds a non-option after -v it treats the rest of the command line as arguments.

On GNU/Linux systems the getopt command is available and (I think) behaves as you want. Don't know about AIX.
 
1 members found this post helpful.
Old 04-03-2012, 09:14 AM   #3
Mark1986
Member
 
Registered: Aug 2008
Location: Netherlands
Distribution: Xubuntu
Posts: 87

Original Poster
Rep: Reputation: 11
Isn't there something to tell getopts that an argument is prohibited for a certain option? Like you can use : to say an argument is mandatory.

I tried some other ways to go around this:

1. Tell getopts that v also needs an argument: v:f:
Outcome: if you don't provide an argument it takes -f as the argument...
2. Try v;f:
Outcome: seems not to work as a way to tell getopts that an argument is prohibited for the option v.
 
Old 04-03-2012, 09:58 AM   #4
catkin
LQ 5k Club
 
Registered: Dec 2008
Location: Tamil Nadu, India
Distribution: Servers: Debian Squeeze and Wheezy. Desktop: Slackware64 14.0. Netbook: Slackware 13.37
Posts: 8,563
Blog Entries: 29

Rep: Reputation: 1179Reputation: 1179Reputation: 1179Reputation: 1179Reputation: 1179Reputation: 1179Reputation: 1179Reputation: 1179Reputation: 1179
The absence of a : after v tells getopts that the v takes no argument.

You can get the behaviour you want with
Code:
#!/bin/bash
#

V_FLAG=
F_FLAG=
FILE=
files=( )
option_regex=^-

while getopts vf: opt
do
  case $opt in
  v)
    V_FLAG=1
    if [[ ! $2 =~ $option_regex ]]; then
        files+=( "$2" )
        shift
    fi
  ;;
  f)
    F_FLAG=1
    FILE="$OPTARG"
  ;;
  \?)
    echo ""
    echo "Usage of mailen:"
    echo "$0 [-v] [-f filename] [file ...]"
    echo ""
    exit 1
  ;;
  esac
done

shift $((OPTIND - 1))
while [[ $# -gt 0 ]]
do
    files+=( "$1" )
    shift
done
echo "DEBUG: files (array): ${files[*]}"

echo "Rest $@"
echo ""
echo "V_FLAG=${V_FLAG}"
echo "F_FLAG=${F_FLAG}"
echo "FILE=${FILE}"

exit 0
 
Old 04-03-2012, 10:09 AM   #5
Mark1986
Member
 
Registered: Aug 2008
Location: Netherlands
Distribution: Xubuntu
Posts: 87

Original Poster
Rep: Reputation: 11
On the version of AIX that I am working on, it does not work. It seems not to handle the += and the ( ) on line 16.
 
Old 04-03-2012, 10:31 AM   #6
catkin
LQ 5k Club
 
Registered: Dec 2008
Location: Tamil Nadu, India
Distribution: Servers: Debian Squeeze and Wheezy. Desktop: Slackware64 14.0. Netbook: Slackware 13.37
Posts: 8,563
Blog Entries: 29

Rep: Reputation: 1179Reputation: 1179Reputation: 1179Reputation: 1179Reputation: 1179Reputation: 1179Reputation: 1179Reputation: 1179Reputation: 1179
Try this change
Code:
FILE=
files=( )
i=0
option_regex=^-

while getopts vf: opt
do
  case $opt in
  v)
    V_FLAG=1
    if [[ ! $2 =~ $option_regex ]]; then
        files[i]="$2"
        let i=i+1
        shift
    fi
  ;;
 
1 members found this post helpful.
Old 04-04-2012, 04:18 AM   #7
Mark1986
Member
 
Registered: Aug 2008
Location: Netherlands
Distribution: Xubuntu
Posts: 87

Original Poster
Rep: Reputation: 11
That did the trick, thank you very much!

Edit: It actually only works in the example given, if I start the script as ./mailen_getopts.sh -f foo foo3 -v foo1 foo2

It gives:

$ ./mailen_getopts.sh -v foo foo3 -f foo1 foo2
Rest foo3 -f foo1 foo2

V_FLAG=1
F_FLAG=
FILE=

So the problem occurs again when I enter an extra argument. The solution seems to be static, not dynamic. Even though with that shift I would think this would be dynamic.

Last edited by Mark1986; 04-04-2012 at 04:25 AM. Reason: Did not work with other forms of input
 
Old 04-04-2012, 06:02 AM   #8
catkin
LQ 5k Club
 
Registered: Dec 2008
Location: Tamil Nadu, India
Distribution: Servers: Debian Squeeze and Wheezy. Desktop: Slackware64 14.0. Netbook: Slackware 13.37
Posts: 8,563
Blog Entries: 29

Rep: Reputation: 1179Reputation: 1179Reputation: 1179Reputation: 1179Reputation: 1179Reputation: 1179Reputation: 1179Reputation: 1179Reputation: 1179
Better to custom program it to solve that:
Code:
#!/bin/bash

V_FLAG=
F_FLAG=
files=( )
option_regex=^-
i=0
set -e

while [[ $# -gt 0 ]]
do
  if [[ $1 =~ $option_regex ]]; then
    opt=${1:1:1}
    optarg=${1:2}
    echo "DEBUG: opt: $opt, optarg: $optarg"
    case $opt in
      v ) 
        V_FLAG=1
        ;;  
      f ) 
        F_FLAG=1
        if [[ $optarg = '' ]]; then
          files[i]="$2"
          let i=i+1
          shift
        else
          files[i]=$optarg
          let i=i+1
        fi  
        ;;  
     * ) 
       echo "Usage: ${0##*/}: [-v] [-f filename] [file ...]"
       exit 1
    esac
  else
    files[i]=$1
    let i=i+1
  fi
  shift
done

echo "DEBUG: V_FLAG: $V_FLAG"
echo "DEBUG: F_FLAG: $F_FLAG"
echo "DEBUG: files (array): ${files[*]}"

exit 0
EDIT: the above allows the -f option argument to be joined to the -f:
Code:
c@CW8:/tmp$ ./try.sh -v foo1 foo2 -f foo3 foo4 -ffoo5
DEBUG: opt: v, optarg: 
DEBUG: opt: f, optarg: 
DEBUG: opt: f, optarg: foo5
DEBUG: V_FLAG: 1
DEBUG: F_FLAG: 1
DEBUG: files (array): foo1 foo2 foo3 foo4 foo5

Last edited by catkin; 04-04-2012 at 06:03 AM.
 
Old 04-16-2012, 08:18 AM   #9
Mark1986
Member
 
Registered: Aug 2008
Location: Netherlands
Distribution: Xubuntu
Posts: 87

Original Poster
Rep: Reputation: 11
I used what you have given me. I finally figured out that indeed getopt or getopts wasn't going to do what I wanted. And I custom crafted the script as I want it to be:

Code:
#!/bin/bash

# Set paramaters and variables
V_FLAG=
F_FLAG=
flags=( )
PREV_FLAG=""
files=( )
i=0
a=0

# Function to add a flag that was used in the flags array
function ADD_FLAG(){
  flags[a]=$1
  let a=a+1
}

# Loop through all arguments given
while [[ $# -gt 0 ]]
do
  opt=${1}
  case $opt in
#If there was an argument -v, mark the flag
    -v ) 
      V_FLAG=1
      PREV_FLAG="v"
      ;;  
#If there was an argument -f, mark the flag
    -f ) 
      F_FLAG=1
      PREV_FLAG="f"
      ;;  
#If the argument was not a -v or -f act as below
    * )
#The argument -f should be the last argument given, if not then exit with the usage details
      if [[ $PREV_FLAG = "f" ]] && [[ $i > 0 ]]
      then
        echo "Usage: mailen_getopts [-v] [-f file] [file ...]"
        exit 1
      fi
#If the previous argument was -f, then this argument is the file first mentioned
      if [[ $PREV_FLAG = "f" ]]
      then
        file=$opt
      else
#If none of the above apply, then add argument into the files array
        files[i]=$opt
        let i=i+1
      fi
#Unmark the flag for previous argument
      PREV_FLAG=
      ;;
    esac
#If the previous flag was not empty, then add the flag to the flags array
  if [[ ! $PREV_FLAG = "" ]]
  then
      ADD_FLAG $PREV_FLAG
  fi
  shift
done

#Echo the debug information
echo "DEBUG: V_FLAG: $V_FLAG"
echo "DEBUG: F_FLAG: $F_FLAG"
echo "DEBUG: flags (array): ${flags[*]}"
echo "DEBUG: file: $file"
echo "DEBUG: files (array): ${files[*]}"

exit 0
This looks for the arguments given. The inflexibility is that you cannot combine arguments like -vf. Something for the future maybe (most likely not ;-) )...

If you have any comments or questions about this script, please let me know.

I am marking this thread as solved. Thank you for your time.
 
Old 04-16-2012, 10:32 AM   #10
catkin
LQ 5k Club
 
Registered: Dec 2008
Location: Tamil Nadu, India
Distribution: Servers: Debian Squeeze and Wheezy. Desktop: Slackware64 14.0. Netbook: Slackware 13.37
Posts: 8,563
Blog Entries: 29

Rep: Reputation: 1179Reputation: 1179Reputation: 1179Reputation: 1179Reputation: 1179Reputation: 1179Reputation: 1179Reputation: 1179Reputation: 1179
Glad you evolved a solution to meet your requirements and thanks for the update
 
  


Reply

Tags
aix, arguments, bash, getopts, scripting


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Unexpected output from my program hida4all Linux - Newbie 1 09-08-2010 05:53 AM
[SOLVED] syslinux unexpected console output lryoung Linux - Kernel 1 07-24-2010 04:55 AM
[SOLVED] Unexpected output from stat --format %h catkin Linux - Software 2 03-07-2010 04:00 AM
Unexpected output from grep zer0x333 Linux - General 12 12-04-2007 11:42 AM
Unexpected output from 'ls' when using glob expressions psiakr3w Linux - General 7 07-22-2004 04:21 AM


All times are GMT -5. The time now is 02:22 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration