Bash: передача параметров с помощью getopts

Я знаю, что это простой вопрос, и я изучал учебники и примеры getopts, но я застрял. Если вы проверите по этой ссылке, вы увидите, что с помощью @fedorqui мне удалось написать код для получения элемента массива в файле.

Однако мне нужно параметризовать входные данные, чтобы скрипт продолжал работать, даже если я изменю порядок входных данных.

Это первый код, который я написал:

#!/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 

Теперь скрипт работает как $ ./tablooku.sh 3 2 tablom.dat и выводит:

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

Что мне нужно сделать, так это перевести этот код, чтобы при вводе $ ./tablooku.sh -r 3 -c 2 tablom.dat скрипт работал.

Это код, который я написал, который застревает при запуске:

#!/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

Не могли бы вы сказать мне, что здесь не так? Когда я запускаю команду, системный вывод:

~/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

Подсказка застревает, и мне приходится использовать ctrl+z, чтобы прервать ожидание. Похоже, мне не удается назначить местоположение файла fi, но я не смог решить проблему.

Примечание. Помните, что -r — это строка, -c — столбец, а последний параметр — это расположение файла, для которого не используется какой-либо код параметра (например, -f).

ОБНОВЛЕНИЕ 1:

Я изменил скобки if ] на ]] и [ на [[. Теперь ошибка unary operator expected исчезла. Теперь приглашение ждет и не печатает -f was triggered, Parameter:... Я все еще использую ctrl+z, чтобы прервать ожидание.

ОБНОВЛЕНИЕ 2:

По предложению @grebneke и @TimK я добавил точки с запятой и изменил параметр fi на fil. Таким образом, я заставляю скрипт работать. Однако осталась одна маленькая проблема. Код работает, если я ввожу $ ./tablooku.sh -r 3 -c 2 -f tablom.dat. Однако мне нужно, чтобы он работал без необходимости писать -f. Является ли это возможным?


person iso_9001_    schedule 17.01.2014    source источник


Ответы (2)


В этих строках:

        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";;

Вы назначаете row/col/fi только для оставшейся части строки. Добавьте точку с запятой после назначения, и она останется назначенной для остальной части скрипта:

        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";;

Изменить <deleted, I misunderstood the question>

Редактировать 2 Чтобы получить оставшиеся аргументы после использования getopts, вы должны shift сделать так:

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"
person grebneke    schedule 17.01.2014
comment
Спасибо за подсказку, но, к сожалению, она не сработала. Результат работы скрипта все тот же: ~/Desktop $ ./go_test.sh -r 3 -c 2 tablom.dat r сработал, Параметр: 3 c сработал, Параметр: 2 (это где подсказка ждет для чего-то) Я не мог сделать приведенный выше код похожим на код :( - person iso_9001_; 17.01.2014
comment
Теперь каким-то образом мне удалось заставить его работать, но мне пришлось использовать -f перед расположением файла. Кроме того, я изменил имя параметра fi на fil. Я имею в виду, что если я использую $ ./tablooku.sh -r 3 -c 2 -f tablom.dat, скрипты работают. Как изменить код, чтобы не нужно было писать -f перед локацией? - person iso_9001_; 17.01.2014
comment
Новый awk, где старый, не возвращает правильные значения. С исходным я могу получить правильное значение, но теперь моя проблема заключается в том, чтобы не использовать -f перед параметром файла. Знаете ли вы, как это сделать (пожалуйста, проверьте мое обновление 2) - person iso_9001_; 17.01.2014
comment
@iso_9001_ См. Редактирование 2 выше. - person grebneke; 17.01.2014
comment
Это не работает. Он застревает в ожидании чего-то. Если я использую while getopts "r:c" opts вместо while getopts "r:c:" opts, он не получает параметр c (я вижу это из вывода эха). Что я сделал: я удалил опцию f. Кроме того, я удалил строку назначения f из блока case. Затем добавлена ​​опция сдвига после esac. Когда я выполняю, он застревает :(. - person iso_9001_; 17.01.2014
comment
Ах понятно. Я должен использовать $1, чтобы присвоить местоположение файловой переменной. Позвольте мне проверить и вернуться - person iso_9001_; 17.01.2014
comment
Теперь это работает, и я очень счастлив :) Большое спасибо за ваши усилия. С уважением - person iso_9001_; 17.01.2014
comment
Пробуя некоторые варианты, я понял, что если я изменю порядок tablom.dat (т.е. перейду к началу параметров), то скрипт вообще не работает. Если я перемещу его в середину -r и -c, будут извлечены все 3 слова в таблице. Можно ли сделать все три места независимыми, чтобы, что бы я ни пытался, я получал правильное значение, или мне нужно сделать tablom.dat параметризованным (например, -f tablom.dat)? - person iso_9001_; 18.01.2014
comment
@iso_9001_: Вы не можете смешивать позиционные аргументы с такими параметрами при использовании getopts. Либо поставьте позиционные аргументы последними, либо сделайте их опциями. Или изучите внешние библиотеки, такие как shflags. - person grebneke; 18.01.2014

Вам не хватает точки с запятой, когда вы устанавливаете $row, $col и $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

Должно быть (точка с запятой перед 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

Без этих точек с запятой ваши команды не выполняются так, как вы ожидаете, как вы можете видеть, глядя на вывод bash -x и изучая строки с -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=

С точкой с запятой:

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

Опять же, посмотрите на строки с -gt. Таким образом, ваши переменные настройки $row, $col и $fi не распространяются без ;.

person Tim Kennedy    schedule 17.01.2014
comment
Спасибо за подробный ответ. Пожалуйста, смотрите update2 на моем OP - person iso_9001_; 17.01.2014