0

I know this is a simple question and I have been examining the getopts tutorials and examples, but I am stuck. If you check this link, you will see that with the help of @fedorqui, I have managed to write the code in order to get an element of an array in a file.

However, what I need is to parameterize the inputs so that the script will continue to work even if I change the order of inputs.

This is the first code I wrote:

#!/bin/bash

file=$3 row=$1 col=$2 str1="Hata: " str2=". satır " str3=". sütun yok"

if [ $row -gt 3 ]
then
    echo $str1$row$str2$col$str3
elif [ $col -gt 3 ]
then
    echo $str1$row$str2$col$str3
else
    awk 'NR==row{print $col}' row=$row col=$col $file
fi 

Now, the script works like $ ./tablooku.sh 3 2 tablom.dat and the output is:

~/Desktop $ ./tablooku.sh 3 2 tablom.dat 
Kopenhag

What I need to do is to translate this code so that when I enter $ ./tablooku.sh -r 3 -c 2 tablom.dat, I get the script work.

This is the code I wrote which stucks upon running:

#!/bin/bash

str1="Hata: "
str2=". satır "
str3=". sütun yok"

while getopts "r:c:f:" opts
do
            case $opts in
            r)     row=$OPTARG echo "-r was triggered, Parameter: $OPTARG";;
            c)     col=$OPTARG echo "-c was triggered, Parameter: $OPTARG";;
            f)     fi=$OPTARG echo "-f was triggered, Parameter: $OPTARG";;
            \?)     printf "Kullanım: %s -r değer -c değer dosya adresi\n" $0
                          exit 2;;
           esac
done

if [ $row -gt 3 ]
then
    echo $str1$row$str2$col$str3
elif [ $col -gt 3 ]
then
    echo $str1$row$str2$col$str3
else
    awk 'NR==r{print $c}' r=$row c=$col $fi
fi

Can you please tell me what is wrong here? When I run the command the system output is:

~/Desktop $ ./go_test.sh -r 3 -c 2 tablom.dat 
-r was triggered, Parameter: 3
-c was triggered, Parameter: 2
./go_test.sh: line 23: [: -gt: unary operator expected
./go_test.sh: line 26: [: -gt: unary operator expected

The prompt stucks and I have to use ctrl+z to break the waiting. It looks like I am failing to assign the file location to fi but I could not solve the problem

Note: Please remember -r is row, - c is column and the last parameter is the file location which does not use any option code (such as -f)

UPDATE 1:

I changed the if brackets ] with ]] and [ with [[. Now the unary operator expected error is gone. Now, the prompt waits and does not print -f was triggered, Parameter:... I still use ctrl+z to break the waiting.

UPDATE 2:

With the suggestion of both @grebneke and @TimK, I added the semi-colons and changed the fi parameter to fil. This way, I get the script working. However, there is one little problem remaining. The code works if I enter $ ./tablooku.sh -r 3 -c 2 -f tablom.dat. However, I need it to run without having to write -f. Is it possible?

Community
  • 1
  • 1
iso_9001_
  • 2,655
  • 6
  • 31
  • 47

2 Answers2

1

In these lines:

        r)     row=$OPTARG echo "-r was triggered, Parameter: $OPTARG";;
        c)     col=$OPTARG echo "-c was triggered, Parameter: $OPTARG";;
        f)     fi=$OPTARG echo "-f was triggered, Parameter: $OPTARG";;

You are assigning row/col/fi for the remainder of the line only. Add a semicolon after the assignment and it will stay assigned for the rest of the script:

        r)     row=$OPTARG; echo "-r was triggered, Parameter: $OPTARG";;
        c)     col=$OPTARG; echo "-c was triggered, Parameter: $OPTARG";;
        f)     fi=$OPTARG; echo "-f was triggered, Parameter: $OPTARG";;

Edit <deleted, I misunderstood the question>

Edit 2 To get the remaining arguments after using getopts, you must shift like this:

while getopts "r:c:" opts
do
...
done

shift $(( $OPTIND-1 ))

# Now, $1, $2 etc are your arguments as you are used to:
$ ./tablooku.sh -r 3 -c 2 tablom.dat
# $1 will be "tablom.dat"
grebneke
  • 4,414
  • 17
  • 24
  • Thanks for the tip but unfortunately, it did not work. The result of the script is still the same: ~/Desktop $ ./go_test.sh -r 3 -c 2 tablom.dat r was triggered, Parameter: 3 c was triggered, Parameter: 2 (this is where the prompt is waiting for something) I couldn't make the above code look like code :( – iso_9001_ Jan 17 '14 at 14:46
  • Now, somehow I managed to get it working but I had to use -f before the file location. Besides, I changed the `fi` parameter name to `fil`. I mean, if I use `$ ./tablooku.sh -r 3 -c 2 -f tablom.dat` the scripts works. How can I change the code so that I do not have to write `-f` before the location? – iso_9001_ Jan 17 '14 at 14:59
  • The new `awk`, where is the old one, doesn't return the correct values. With the original one I can get the correct value but now my problem is to not use `-f` before the file parameter. Do you know how to do this (please check my update 2) – iso_9001_ Jan 17 '14 at 15:15
  • @iso_9001_ Please see Edit 2 above – grebneke Jan 17 '14 at 15:40
  • This does not work. It stucks waiting for something. If I use `while getopts "r:c" opts` instead of `while getopts "r:c:" opts` it does not get the c parameter (I can see it from echo output). What I did: I removed the f option. Also, I removed f assignment line from case block. Then added shift option after esac. When I execute, it stucks :(. – iso_9001_ Jan 17 '14 at 15:46
  • Ahh, I see. I have to use $1 in order to assign the location to file variable. Let me test and get back – iso_9001_ Jan 17 '14 at 15:50
  • 1
    Now it works and I am really happy :) Thank you very much for your efforts. Kind Regards – iso_9001_ Jan 17 '14 at 15:54
  • While trying some options, I realized that if I change the order of `tablom.dat` (i.e. move to the start of parameters), the script does not work at all. If I move it into the middle of `-r` and `-c`, the whole 3 words in the table are retrieved. Is it possible to make all three place independent so whatever I try, I get the correct value or do I have to make `tablom.dat` parameterized (such as `-f tablom.dat`)? – iso_9001_ Jan 18 '14 at 08:10
  • @iso_9001_: You cannot mix positional arguments with options like that when using `getopts`. Either put positional arguments last, or make them options. Or research external libraries like [shflags](http://code.google.com/p/shflags/wiki/Documentation10x) – grebneke Jan 18 '14 at 10:02
0

You're missing a semi-colon in where you're setting $row, $col, and $fi.

        case $opts in
        r)     row=$OPTARG echo "-r was triggered, Parameter: $OPTARG";;
        c)     col=$OPTARG echo "-c was triggered, Parameter: $OPTARG";;
        f)     fi=$OPTARG echo "-f was triggered, Parameter: $OPTARG";;
        \?)     printf "Kullanım: %s -r değer -c değer dosya adresi\n" $0
                      exit 2;;
       esac

Should be (semi-colon before the echo):

        case $opts in
        r)     row=$OPTARG ; echo "-r was triggered, Parameter: $OPTARG";;
        c)     col=$OPTARG ; echo "-c was triggered, Parameter: $OPTARG";;
        f)     fi=$OPTARG ; echo "-f was triggered, Parameter: $OPTARG";;
        \?)     printf "Kullanım: %s -r değer -c değer dosya adresi\n" $0
                      exit 2;;
       esac

Without those semi-colons, your commands are not being run as you would expect, as you can see looking at the output of bash -x, and examine the lines with -gt:

bash-[576]$ bash -x foo.bash -r 3 -c 3 -f foo
+ str1='Hata: '
+ str2='. satır '
+ str3='. sütun yok'
+ getopts r:c:f: opts
+ case $opts in
+ row=3
+ echo '-r was triggered, Parameter: 3'
-r was triggered, Parameter: 3
+ getopts r:c:f: opts
+ case $opts in
+ col=3
+ echo '-c was triggered, Parameter: 3'
-c was triggered, Parameter: 3
+ getopts r:c:f: opts
+ case $opts in
+ fi=foo
+ echo '-f was triggered, Parameter: foo'
-f was triggered, Parameter: foo
+ getopts r:c:f: opts
+ '[' -gt 3 ']'
foo.bash: line 18: [: -gt: unary operator expected
+ '[' -gt 3 ']'
foo.bash: line 20: [: -gt: unary operator expected
+ awk 'NR==r{print $c}' r= c=

With the semi-colons:

bash-[574]$ bash -x foo.bash -r 3 -c 3 -f foo
+ str1='Hata: '
+ str2='. satır '
+ str3='. sütun yok'
+ getopts r:c:f: opts
+ case $opts in
+ row=3
+ echo '-r was triggered, Parameter: 3'
-r was triggered, Parameter: 3
+ getopts r:c:f: opts
+ case $opts in
+ col=3
+ echo '-c was triggered, Parameter: 3'
-c was triggered, Parameter: 3
+ getopts r:c:f: opts
+ case $opts in
+ fi=foo
+ echo '-f was triggered, Parameter: foo'
-f was triggered, Parameter: foo
+ getopts r:c:f: opts
+ '[' 3 -gt 3 ']'
+ '[' 3 -gt 3 ']'
+ awk 'NR==r{print $c}' r=3 c=3 foo

Again, look at the lines with -gt. So your variable settings of $row, $col, and $fi are not propagating without the ;.

Tim Kennedy
  • 5,980
  • 1
  • 21
  • 16