2017-02-20 5 views
2

Я пытаюсь создать простую функцию на macOS Sierra, которая подсчитывает символы в строке. Это прекрасно работает (добавлено к моему bashrc файл):В Bash, почему использование getopts в функции работает только один раз?

function cchar() { 
    str=$1 
    len=${#str} 
    echo "string is $len char long" 
} 

$ cchar "foo" 
string is 3 char long 

Я пытаюсь расширить его с -a вариант, поэтому я добавил это к моей функции (и прокомментированы остальные из для тестирования):

while getopts "a:" opt; do 
    case $opt in 
     a) 
      echo "-a param: $OPTARG" >&2 
      ;; 
    esac 
done 

После некоторого тестирования во время написания этого, я заметил, каждый раз, когда я бегу cchar -a "test", я должен запустить его без опций (cchar) в противном случае следующий раз, когда я запустить его с опцией -a, он не признает возможность.

$ cchar 

$ cchar -a "foo" 
-a param: foo 

$ cchar -a "foo" 

$ cchar 

$ cchar -a "foo" 
-a param: foo 
+0

Моя конечная цель состоит в том, чтобы параметр '-a' возвращал только число строк в виде int для использования в других функциях. Я столкнулся с этой проблемой, пытаясь это сделать. –

+0

Я попробовал 'unset opt' после цикла' while' в случае, когда var запоминается между завершением функции, не исправил ее. Кроме того, разные перенаправления не имели положительного эффекта ('& 2> 1','> & 1', [blank]) –

+0

Перенаправления не являются параметрами командной строки. Почему они что-то влияют? – rici

ответ

6

Вы должны сбросить переменную OPTIND, которая отслеживает текущий позиционного числа аргументов. Этого достаточно, чтобы сделать эту переменную локальной для вашей функции.

+0

Это решило мою проблему, спасибо. –

+0

См. [Getopts] (https://www.gnu.org/software/bash/manual/bash.html#index-getopts) в руководстве Bash. В нем говорится, в частности: _ Каждый раз, когда он вызывается, getopts помещает следующий параметр в переменную оболочки 'name', инициализирует' name', если она не существует, и индекс следующего аргумента, который должен быть обработан в переменной OPTIND. OPTIND инициализируется до 1 при каждом вызове оболочки или скрипта оболочки. ... Оболочка не сбрасывает OPTIND автоматически; он должен быть вручную сброшен между несколькими вызовами в getopts в рамках одного и того же вызова оболочки, если будет использоваться новый набор параметров. –

+1

Да, 'getopts' предназначен для анализа параметров сценария, а не для аргументов функции. Но он будет работать так же хорошо с локальными переменными (хотя 'local OPTIND = 1', вероятно, лучше, на всякий случай.) – rici

0

Окончательный код, который я закончил с использованием:

# Count characters in a string 
function cchar() { 
    local OPTIND 

    while getopts "a:" opt; do 
     case $opt in 
      a) 
       echo ${#OPTARG} 
       return 
       ;; 
     esac 
    done 

    echo "string is ${#1} characters long" 
} 

$ cchar "foo bar" 
string is 7 characters long 

$ cchar -a "foo bar" 
7 

Примечание: я должен был использовать return вместо exit, когда получены из .bashrc, exit закроет текущую оболочку.

+1

Обратите внимание, что вы можете просто использовать: 'echo 'string - $ {# 1} char long" 'в длинной форме (и' echo "$ {# OPTARG}"> & 2' в короткой форме). Есть ли веская причина писать стандартную ошибку в короткой форме? Было бы более обычным писать стандартный вывод - вы можете перенаправить вывод на стандартную ошибку при вызове функции, если это то, что вам нужно. –

+0

Вы правы, спасибо. Я писал stderr, потому что [принятый ответ в этом вопросе] (http://stackoverflow.com/questions/14447406/bash-shell-script-check-for-a-flag-and-grab-its-value) использовался Это. –