2016-09-02 4 views
-1
function generateFileList { 

for entry in "$ORIGINATION_PATH"/* 
    do 
     entry=${entry%.*} # retain the part before the dot 
     entry=${entry##*/} # retain the part after the last slash 
     if [ $(contains "${FILENAME[@]}" $entry) == "n" ]; then 
      FILENAME[$fn_counter]=$entry 
      fn_counter=(expr $fn_counter + 1) 
       echo $entry "added to filelist" 
      echo ${FILENAME[$fn_counter]} 
     fi 

    done 
NUMBER_OF_FILES=$(expr ${#FILENAME[@]} + 1)} 

У меня есть эта функция. У моего ORIGINATION_PATH есть много файлов. Однако, когда я вызываю эту функцию, мой массив $ FILENAME заполняется только одной записью. Почему? Внутри функции все кажется прекрасным, и кажется, что массив $ FILENAME получает все значения, которые ему нужно получить, но когда я проверяю вне функции, я получаю только одно значение в $ FILENAME araybash script function scope

+1

Как написано, определение 'generateFileList' потерпит неудачу. Кроме того, в коде есть неопределенные переменные. См. [Как создать минимальный, завершенный и проверяемый пример] (http://stackoverflow.com/help/mcve), а затем обновите вопрос. – John1024

+1

В стороне - рассмотрите использование имен нижнего регистра для собственных переменных. См. [Обсуждение переменных среды POSIX для переменных среды] (http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html), параграф 4, отметив, что имена всех шапок используются для переменных со значением для системы и shell, и что другие имена зарезервированы для приложений. Поскольку установка переменной оболочки будет перезаписывать любую переменную среды с похожим именем, это соглашение обязательно применимо и к ним. –

ответ

1

Проблемы с вашим кодом и предложениями для улучшения:

  1. вы должны инициализировать ${FILENAME[@]} пустой массив (или в самом, если вы всегда хотите, чтобы функция, чтобы создать новый список файлов с нуля функции, или перед вызовом функции, если вы хотите, чтобы иметь возможность для создания составного списка файлов путем повторного вызова функции в разных базовых каталогах).
  2. Вы должны инициализировать $fn_counter до нуля до начала цикла. Или, для идеи составного наращивания, к числу элементов, находящихся в настоящее время в ${FILENAME[@]}. Собственно, другим, возможно, предпочтительным решением было бы полностью удалить переменную $fn_counter и заменить ее на ${#FILENAME[@]}, так как она всегда должна быть равна этому значению.
  3. В строке fn_counter=(expr $fn_counter + 1) вы назначаете $fn_counter массиву, а не увеличиваете его. Это потому, что вы забыли доллар перед открытой круглой скобкой. Если вы запустили fn_counter=$(expr $fn_counter + 1), тогда это сработает. Но есть лучший способ увеличить числовую переменную: let ++fn_counter.
  4. В арифметических выражениях вам не нужны переменные префикса доллара. Так, например, мы можем сказать ${FILENAME[fn_counter]} вместо ${FILENAME[$fn_counter]}.
  5. Вы пытаетесь повторить элемент ${FILENAME[@]}, который был добавлен только в текущую итерацию, но с индексом $fn_counterпосле он был увеличен, что неверно. Вы можете решить это, вычитая из него 1, то есть echo "${FILENAME[fn_counter-1]}". Или, если удалить $fn_counter, echo "${FILENAME[${#FILENAME[@]}-1]}".
  6. При назначении $NUMBER_OF_FILES, я не знаю, почему вы добавляете 1 к ${#FILENAME[@]}. Количество элементов в массиве ${FILENAME[@]} должно быть равно количеству файлов, не требуя приращения, нет? Я рекомендую полностью удалить эту переменную, так как это значение можно получить непосредственно как ${#FILENAME[@]}.
  7. Я рекомендую вам передать входные данные в качестве аргументов (например, передать $ORIGINATION_PATH в качестве аргумента) и использовать ключевое слово local, чтобы уменьшить вероятность переменных столкновений между функциями. Глобалы являются дефолтом в bash, что создает опасные возможности для разных функций наступать друг на друга. Например, представьте, если функция contains (при условии, что она является функцией оболочки) присвоила значение глобальной переменной $entry.
  8. Я рекомендую всегда с использованием команды [[, а не [, так как он более мощный, и хорошо быть последовательным.
  9. Как написано, ваш скрипт не будет работать корректно в пустом каталоге. Вы можете проверить заранее, если каталог пуст (например, [[ -n "$(find "$ORIGINATION_PATH" -maxdepth 0 -empty)" ]]). Другим решением является установка nullglob. Другое решение - пропустить глобусные слова, которые фактически не существуют (например, if [[ ! -e "$entry" ]]; then continue; fi;).
  10. Всегда разворачивайте переменные разложения для защиты от разбиения слов, которое происходит после расширения переменной.Например, звонок contains должен быть contains "${FILENAME[@]}" "$entry" (обратите внимание на двойное цитирование около $entry). Единственными исключениями являются (1) при назначении строковой переменной строковой переменной, то есть new=$old, и в этом случае вам не нужно ее цитировать, и (2) при расширении числовой переменной, которая гарантируется, что она не будет повреждена расщепление слов.

Вот рабочий раствор, заполняя недостающие части:

function contains { 

    local target="${@:$#:1}"; 
    local -a array=("${@:1:$#-1}"); 
    local elem=''; 

    for elem in "${array[@]}"; do 
     if [[ "$elem" == "$target" ]]; then 
      echo 'y'; 
      return; 
     fi; 
    done; 

    echo 'n'; 

} ## end contains() 

function generateFileList { 

    local path="$1"; 
    local entry=''; 

    for entry in "$path"/*; do 
     if [[ ! -e "$entry" ]]; then continue; fi; 
     entry=${entry%.*}; ## retain the part before the dot 
     entry=${entry##*/}; ## retain the part after the last slash 
     if [[ "$(contains "${FILENAME[@]}" "$entry")" == 'n' ]]; then 
      FILENAME[${#FILENAME[@]}]=$entry; 
      echo "$entry added to filelist"; 
      echo "${FILENAME[${#FILENAME[@]}-1]}"; 
     fi; 
    done; 

} ## end generateFileList() 

ORIGINATION_PATH='...'; 
FILENAME=(); ## build up result on global ${FILENAME[@]} var 
generateFileList "$ORIGINATION_PATH"; 

echo "\${#FILENAME[@]} == ${#FILENAME[@]}"; 
echo "\${FILENAME[@]} == (${FILENAME[@]})";