【问题标题】:Deleting specific values from an array in ksh从 ksh 中的数组中删除特定值
【发布时间】:2010-01-21 00:07:26
【问题描述】:

我有一个自定义的 .profile,我在 ksh 中使用,下面是我创建的一个函数,用于在名称过于复杂或过长的目录中来回跳转。

如您所见,路径名存储在一个数组 (BOOKMARKS[]) 中以跟踪它们并在以后引用它们。我希望能够使用 case 语句(或必要时使用 OPTARG)从数组中删除某些值,这样我只需键入 bmk -d # 即可删除关联索引处的路径。

我一直在摆弄array +A and -A,但它最终搞砸了我的数组(注释掉的代码中留下的内容可能并不漂亮......我没有校对它)。

关于如何创建该功能的任何建议/提示?谢谢!

# To bookmark the current directory you are in for easy navigation back and forth from multiple non-aliased directories
# Use like 'bmk' (sets the current directory to a bookmark number) to go back to this directory, i.e. type 'bmk 3' (for the 3rd)
# To find out what directories are linked to which numbers, type 'bmk -l' (lowercase L)
# For every new directory bookmarked, the number will increase so the first time you run 'bmk' it will be 1 then 2,3,4...etc. for every consecutive run therea
fter
# TODO: finish -d (delete bookmark entry) function
make_bookmark()
{
        if [[ $# -eq 0 ]]; then
                BOOKMARKS[${COUNTER}]=${PWD}
                (( COUNTER=COUNTER+1 ))
        else
                case $1 in
                        -l)     NUM_OF_ELEMENTS=${#BOOKMARKS[*]}

                                while [[ ${COUNTER} -lt ${NUM_OF_ELEMENTS} ]]
                                do
                                        (( ACTUAL_NUM=i+1 ))
                                        echo ${ACTUAL_NUM}":"${BOOKMARKS[${i}]}
                                        (( COUNTER=COUNTER+1 ))
                                done
                                break ;;


                       #-d)    ACTUAL_NUM=$2
                                #(( REMOVE=${ACTUAL_NUM}-1 ))
                                #echo "Removing path ${BOOKMARKS[${REMOVE}]} from 'bmk'..."
                                #NUM_OF_ELEMENTS=${#BOOKMARKS[*]}

                                #while [[ ${NUM_OF_ELEMENTS} -gt 0 ]]
                                #do
                                        #if [[ ${NUM_OF_ELEMENTS} -ne ${ACTUAL_NUM} ]]; then
                                        #       TEMP_ARR=$(echo "${BOOKMARKS[*]}")
                                        #       (( NUM_OF_ELEMENTS=${NUM_OF_ELEMENTS}-1 ))
                                        #fi
                                        #echo $TEMP_ARR
                                #done
                                #break
                                #for VALUE in ${TEMP_ARR}
                                #do
                                #       set +A BOOKMARK ${TEMP_ARR}
                                #done
                                #echo ${BOOKMARK[*]}

                                #break ;;

                        *)      (( INDEX=$1-1 ))
                                cd ${BOOKMARKS[${INDEX}]}
                                break ;;
                esac
        fi
}

【问题讨论】:

    标签: arrays function ksh


    【解决方案1】:

    Korn shell(以及 Bash 和其他)中的数组是稀疏的,因此如果您使用 unset 删除数组的成员,您将无法使用数组的大小作为最后一个的索引成员和其他限制。

    这里有一些有用的 sn-ps(第二个 for 循环是您可以立即使用的东西):

    array=(1 2 3)
    unset array[2]
    echo ${array[2]}          # null
    indices=(${!array[@]})    # create an array of the indices of "array"
    size=${#indices[@]}       # the size of "array" is the number of indices into it
    size=${#array[@]}         # same
    echo ${array[@]: -1}      # you can use slices to get array elements, -1 is the last one, etc.
    for element in ${array[@]}; do    # iterate over the array without an index
    
    for index in ${indices[@]}        # iterate over the array WITH an index
    do
        echo "Index: ${index}, Element: ${array[index]}"
    done
    
    for index in ${!array[@]}         # iterate over the array WITH an index, directly
    

    最后一个可以消除对计数器的需要。

    这里有一些更方便的技巧:

    array+=("new element")    # append a new element without referring to an index
    ((counter++))             # shorter than ((counter=counter+1)) or ((counter+=1))
    if [[ $var == 3 ]]        # you can use the more "natural" comparison operators inside double square brackets
    while [[ $var < 11 ]]     # another example
    echo ${array[${index}-1]  # math inside an array subscript
    

    这一切都假设 ksh93,有些东西在早期版本中可能无法正常工作。

    【讨论】:

    • 太棒了...非常感谢丹尼斯!这些真的很方便知道,我会尽快使用它们:)
    【解决方案2】:

    您可以使用未设置。例如删除数组元素 1

    unset array[0]
    

    删除整个数组

    unset array
    

    【讨论】:

      【解决方案3】:

      关于上一个答案的一些注意事项:

      首先:我一直看到这个错误。当你提供一个数组元素来“取消设置”时,你必须引用它。考虑:

      $ echo foo > ./a2
      $ ls a[2]
      a2
      $ a2="Do not delete this"
      $ a=(this is not an array)
      $ unset -v a[2]
      $ echo "a2=${a2-UNSET}, a[]=${a[@]}"
      a2=UNSET a[]=this is not an array
      

      发生了什么?通配符。您显然想删除 a[] 的元素 2,但是 shell 语法是这样的,shell 首先检查当前目录中是否存在与 glob 模式“a[2]”匹配的文件。如果找到匹配项,它会将 glob 模式替换为该文件名,然后您最终会根据当前目录中存在的文件来决定要删除哪个变量。

      这太愚蠢了。但显然,这不是任何人都愿意解决的问题,而且过去 3 年的各种文档和示例代码中都出现了该错误。

      接下来是一个相关的问题:使用您喜欢的任何键在关联数组中插入元素很容易。但是移除这些元素比较困难:

      typeset -A assoc
      key="foo] bar"
      assoc[$key]=3    #No problem!
      unset -v "assoc[$key]"    #Problem!
      

      在 bash 中你可以这样做:

      unset -v "assoc[\$key]"
      

      在 Korn Shell 中,您必须这样做:

      unset -v "assoc[foo\]\ bar]"
      

      所以在你的键包含语法字符的情况下它会变得有点复杂。

      【讨论】:

        猜你喜欢
        • 2016-07-13
        • 1970-01-01
        • 2014-03-21
        • 2020-07-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多