在ksh中从数组中删除特定的值

6

我有一个定制的.profile文件,用于在ksh中使用,下面是我创建的一个函数,用于快速前往或返回名称过于复杂或过长的目录。

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

我已经尝试过array +A 和 -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
}
3个回答

5

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

以下是一些有用的代码片段(第二个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的,某些内容可能在早期版本中无法正常工作。

太棒了...非常感谢Dennis!这些真的很有用,我会尽快使用它们 :) - Sean

2
你可以使用unset. eg删除数组元素1。
unset array[0]

删除整个数组

unset array

1

关于之前的回答,有一些需要注意的地方:

首先:我经常看到这个错误。当您将数组元素提供给“unset”时,必须将其用引号括起来。 例如:

$ 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

发生了什么?Globbing。显然您想删除a[]的第2个元素,但由于Shell语法的缘故,Shell首先检查当前目录是否有与" a[2] "匹配的文件。如果找到匹配项,则将glob模式替换为该文件名,您最终会根据当前目录中存在哪些文件来决定要删除哪个变量。
这是非常愚蠢的。但显然没有人费心去解决这个问题,而这个错误出现在过去30年的所有文档和示例代码中。
接下来是一个相关的问题:易于使用任何键插入关联数组中的元素。但是删除这些元素却更加困难。
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]"

如果您的键包含语法字符,则情况会变得更加复杂。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接