Решено: getopts, bash 2.03 (В bash-3 работает. В сабже - нет =(()

На самом деле это единственный раздел про unix на этом форуме

Модераторы: /dev/random, Модераторы разделов

Аватара пользователя
drag0n
Сообщения: 156
Статус: Дракон-линуксоид
ОС: Slackware Linux

Решено: getopts, bash 2.03

Сообщение drag0n »

Имеется bash-скрипт принимающий два ключа -m и -d. У ключей может быть аргумент - имя файла, а может и не быть, тогда используется умолчальное имя файла. Разбор ключей я сделал через getopts следующим образом:

Код: Выделить всё

#!/bin/bash

while getopts ":m:d:" OPTN; do
    case $OPTN in
        m)
            if [ "$OPTARG" == "-d" ]; then
                ((OPTIND=$OPTIND - 1))
            else
                MAIN_DIC=$OPTARG
            fi
            USE_MAIN=1
    ;;
        d)
            if [ "$OPTARG" == "-m" ]; then
                ((OPTIND=$OPTIND - 1))
            else
                ADV_DIC=$OPTARG
            fi
            USE_ADV=1
    ;;
        ":")
            case $OPTARG in
                m)
                USE_MAIN=1
            ;;
                d)
                USE_ADV=1
            ;;
            esac
    ;;
        "?")
            echo "$OPTARG - unknown option!"
            echo
            exit 1
    ;;
        *)
            echo "Unknown error while processing options!"
            exit 1
    ;;
    esac
done

shift $(($OPTIND - 1))


Смотрим, что за аргумент у первого ключа. Если этот аргумент совпадает со вторым ключем, то мы делаем вывод, что первый ключ пустой - уменьшаем OPTIND на единицу, чтобы getopts обработал наш вторй ключ. Если аргумент у первого ключа не совпадает со вторым ключем, значит нам дали путь к файлу для первого ключа. Если у второго ключа нет аргументов, то мы обрабатываем это в ветке ":"). Естественно, первым ключем может быть как -m, так и -d, любой из этих ключей может иметь дополнительный аргумент или не иметь. Например:

Код: Выделить всё

./script -m -d
./script -d -m file1
./scripts -d file2 -m
./script -m file 1 -d file 2

Данный код работает в точности как и было описано, в bash 3 версии. Но в bash версии 2.03 имеются некоторые траблы. Как я смог установить, переменная OPTIND уменьшается на единицу, но такое ощущение, что bash ее новое значение игнорирует. Соответственно, если мы получили ключи вида ./script -m -d, то ключ -d не обрабатывается getopts, ведь он прошел как аргумент для первого ключа!
Есть ли какое-нибудь решение данной проблемы? Может быть это малоизвестный баг bash-2.03??
После каталога /etc понимаешь, что реестр - место, откуда нормальными не возвращаются.
Спасибо сказали:
Аватара пользователя
diesel
Бывший модератор
Сообщения: 5989
ОС: OS X, openSuSE, ROSA, Debian

Re: Решено: getopts, bash 2.03

Сообщение diesel »

Код: Выделить всё

bash  tmp.sh -m marg -d darg -e earg
OPTN m
OPTARG marg
OPTIND 3
m
OPTN: d; OPTARG: darg; OPTIND: 5
-----
OPTN e
OPTARG earg
OPTIND 7
e
-----


Код: Выделить всё

cat tmp.sh
#!/bin/bash

while getopts "m:d:e:" OPTN; do
    echo "OPTN" $OPTN;
    echo "OPTARG" $OPTARG;
    echo "OPTIND" $OPTIND;

    case $OPTN in
        m)
            echo m
            getopts "m:d:e:" OPTN;
            echo "OPTN: $OPTN; OPTARG: $OPTARG; OPTIND: $OPTIND"
           ;;
        d)
            echo d;;
        e)
            echo e ;;
    esac
    echo "-----";
done


Вроде как все работает так как описано в man'е, у меня 2.05
Спасибо сказали:
watashiwa_daredeska
Бывший модератор
Сообщения: 4038
Статус: Искусственный интеллект (pre-alpha)
ОС: Debian GNU/Linux

Re: Решено: getopts, bash 2.03

Сообщение watashiwa_daredeska »

Я бы рекомендовал привести опции к стандартному виду в плане использования и заменить getopts на getopt.

Код: Выделить всё

#!/bin/sh

ARGS=$(getopt -n $(basename "$0") -o 'dD:mM:' -- "$@")
[ $? = 0 ] || exit 1
eval set -- "$ARGS"

while [ "$1" != -- ]; do
    case "$1" in
        -d) USE_ADV=1;;
        -D) ADV_DIC=$2; shift; USE_ADV=1;;
        -m) USE_MAIN=1;;
        -M) MAIN_DIC=$2; shift; USE_MAIN=1;;
    esac
    shift
done
shift

echo "USE_ADV=$USE_ADV"
echo "ADV_DIC=$ADV_DIC"
echo "USE_MAIN=$USE_MAIN"
echo "MAIN_DIC=$MAIN_DIC"

user@host

$ ./script USE_ADV= ADV_DIC= USE_MAIN= MAIN_DIC= $ ./script -d -m USE_ADV=1 ADV_DIC= USE_MAIN=1 MAIN_DIC= $ ./script -d -M main_dic USE_ADV=1 ADV_DIC= USE_MAIN=1 MAIN_DIC=main_dic $ ./script -x script: invalid option -- x
Спасибо сказали:
Аватара пользователя
drag0n
Сообщения: 156
Статус: Дракон-линуксоид
ОС: Slackware Linux

Re: Решено: getopts, bash 2.03

Сообщение drag0n »

Всем спасибо. Проблему решил методом watashiwa_daredeska
После каталога /etc понимаешь, что реестр - место, откуда нормальными не возвращаются.
Спасибо сказали: