2

I want to write a bash script :

schedsim.sh [-h] [-c x] -i pathfile

Where :

• -h: print the current username.

• -c x : get an option-argument x and print out (x + 1). If no argument was found, print the default value is 1.

• -i pathfile: print the size of pathfile. The pathfile is a required argument. If no argument was found, print out an error message.

This is what I've done so far :

x=""
path=""
while getopts ":hc:i:" Option
do
case $Option in
h) echo -e "$USER\n"
;;
c) x=$optarg+1
;;
i) path=$(wc -c <"$optarg")
;;
esac
done

if [ -z "$x"] 
then
 echo -e "$x\n"
else
 echo 1
fi

if [ -z "$path"] 
then
 echo $path
else
 echo "Error Message"
 exit 1
fi

How to finish the option-argument,required-argument part and the error message part?

2
  • Maybe instead of looping you could get all the values and set them as variables first. Then you could check if i was passed, before doing any other processing: if [ -z "$i" ]..., and print a usage when it's not. Commented Sep 28, 2015 at 15:33
  • I edited it,was I right ? Commented Sep 28, 2015 at 16:07

2 Answers 2

2

A rewrite:

while getopts ":hc:i:" Option; do
    case $Option in
        h)  echo "$USER"
            ;;
        c)  x=$(($OPTARG + 1))
            ;;
        i)  if [[ -f $OPTARG ]]; then
                size=$(wc -c <"$OPTARG")
            else
                echo "error: no such file: $OPTARG"
                exit 1
            fi 
            ;;
    esac
done

if [[ -z $x ]]; then
    echo "you used -c: the result is $x"
fi

if [[ -z $size ]]; then
    echo "you used -i: the file size is $size"
fi

Notes:

  • OPTARG must be in upper case.
  • you need $((...)) for bash arithmetic
  • check that the file exists before using it
  • use a sensible filename (path does not represent the size of a file)
  • there must be a space before ]
  • echo -e "value\n" is too much work: you just want echo "value" unless you want to process escape sequences in the value:

    $ var="foo\tbar\rbaz"
    $ echo "$var"
    foo\tbar\rbaz
    $ echo -e "$var\n"
    baz bar
    
    $ 
    

Update: responding to comments: simplified and more complete option handling; expanded error handling.

#!/bin/bash
declare -A given=([c]=false [i]=false)
x=0
path=""

while getopts ":hc:i:" Option; do
    case $Option in
        h)  echo "$USER"
            ;;
        c)  x=$OPTARG
            given[c]=true
            ;;
        i)  path=$OPTARG
            given[i]=true
            ;;
        :)  echo "error: missing argument for option -$OPTARG"
            exit 1
            ;;
        *)  echo "error: unknown option: -$OPTARG"
            exit 1
            ;;
    esac
done

# handle $x
if [[ ! $x =~ ^[+-]?[[:digit:]]+$ ]]; then
    echo "error: your argument to -c is not an integer"
    exit 1
fi
if ! ${given[c]}; then
    printf "using the default value: "
fi
echo $(( 10#$x + 1 ))

# handle $path
if ! ${given[i]}; then
    echo "error: missing mandatory option: -i path"
    exit 1
fi
if ! [[ -f "$path" ]]; then
    echo "error: no such file: $path"
    exit 1
fi
echo "size of '$path' is $(stat -c %s "$path")"
Sign up to request clarification or add additional context in comments.

4 Comments

Note that you should check that the argument of -c is a number (otherwise it is subject to arbitrary code execution), and maybe prepend 10# to avoid the August error.
@gniourf_gniourf so how to check it ?
@DươngAnhKhoa: Something like [[ $OPTARG = +([[:digit:]]) ]] || { echo "Argument to -c is not a number"; exit 1; }.
where is the part "If no argument was found, print the default value is 1. " ? Thanks for help !
0

I think what you're looking for is "argument parsing" in bash. Please take a look at this excellent answer: https://stackoverflow.com/a/14203146/3380671

Regarding this required/optional part: initialize the variable with an empty string and just check the string's length after the argument parsing.

FILE_PATH=""
# Do the argument parsing here ...
# And then:
if [ -z "$FILE_PATH" ]
then
  echo "Please specify a path. Aborting."
  exit 1
fi

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.