bash脚本函数范围

时间:2016-09-02 21:50:20

标签: linux bash function

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 aray中获得一个值

1 个答案:

答案 0 :(得分: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. 您不必在算术表达式中使用dollar-prefix变量。因此,例如,我们可以说${FILENAME[fn_counter]}而不是${FILENAME[$fn_counter]}
  5. 您正在尝试回显刚刚在当前迭代中添加的${FILENAME[@]}元素,但在之后使用$fn_counter 对其进行索引会增加,这是不正确的。您可以通过从中减去1来解决此问题,即echo "${FILENAME[fn_counter-1]}"。或者,如果删除$fn_counterecho "${FILENAME[${#FILENAME[@]}-1]}"
  6. 分配$NUMBER_OF_FILES时,我不知道你为什么要向${#FILENAME[@]}添加1。 ${FILENAME[@]}数组中的元素数应该等于文件数,不需要增量,不是吗?我建议完全删除此变量,因为该值可以直接以${#FILENAME[@]}
  7. 的形式访问
  8. 我建议您将输入作为参数传递(例如,将$ORIGINATION_PATH作为参数传递)并使用local关键字来降低函数之间变量冲突的可能性。全局变量是bash中的默认值,它为不同的函数创建了危险的可能性,以便踩到彼此的脚趾。例如,假设contains函数(假设它是一个shell函数)为全局$entry变量赋值。
  9. 我建议总是使用[[命令而不是[,因为它更强大,并且保持一致性很好。
  10. 如上所述,您的脚本无法在空目录上正常运行。如果目录为空(例如[[ -n "$(find "$ORIGINATION_PATH" -maxdepth 0 -empty)" ]]),您可以提前测试。另一种解决方案是设置nullglob。另一个解决方案是跳过实际不存在的glob字(例如if [[ ! -e "$entry" ]]; then continue; fi;)。
  11. 始终双引号变量扩展以防止在变量扩展后发生的单词拆分。例如,contains调用应为contains "${FILENAME[@]}" "$entry"(请注意$entry周围的双引号)。唯一的例外是(1)将字符串变量分配给字符串变量,即new=$old,在这种情况下,您不必引用它,以及(2)扩展数字变量时,保证不被分词破坏。
  12. 这是一个有效的解决方案,填补了缺失的部分:

    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[@]})";