简体   繁体   English

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

[英]Deleting specific values from an array in ksh

I have a customized .profile that I use in ksh and below is a function that I created to skip back and forth from directories with overly complicated or long names. 我有一个我在ksh中使用的自定义.profile,下面是我创建的一个函数,可以从具有过于复杂或长名称的目录中来回跳过。

As you can see, the pathnames are stored in an array ( BOOKMARKS[] ) to keep track of them and reference them at a later time. 如您所见,路径名存储在一个数组( BOOKMARKS[] )中以跟踪它们并在以后引用它们。 I want to be able to delete certain values from the array, using a case statement (or OPTARG if necessary) so that I can just type bmk -d # to remove the path at the associated index. 我希望能够使用case语句(或必要时的OPTARG)从数组中删除某些值,这样我只需键入bmk -d #即可删除相关索引处的路径。

I have fiddled around with array +A and -A , but it just wound up screwing up my array (what is left in the commented out code may not be pretty...I didn't proofread it). 我已经摆弄了array +A and -A ,但它只是搞砸了我的阵列(注释掉的代码中剩下的可能不是很漂亮......我没有校对它)。

Any suggestions/tips on how to create that functionality? 有关如何创建该功能的任何建议/提示? Thanks! 谢谢!

# 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 in the Korn shell (and Bash and others) are sparse, so if you use unset to delete members of the array, you won't be able to use the size of the array as an index to the last member and other limitations. Korn shell(以及Bash和其他)中的数组是稀疏的,因此如果使用unset删除数组的成员,则无法使用数组的大小作为最后一个成员的索引和其他限制。

Here are some useful snippets (the second for loop is something you might be able to put to use right away): 这里有一些有用的片段(第二个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

That last one can eliminate the need for a counter. 最后一个可以消除对计数器的需要。

Here are a couple more handy techniques: 以下是一些更方便的技巧:

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

This all assumes ksh93, some things may not work in earlier versions. 这一切都假设ksh93,有些东西可能在早期版本中不起作用。

you can use unset. 你可以使用unset。 eg to delete array element 1 例如,删除数组元素1

unset array[0]

to delete entire array 删除整个数组

unset array

A few caveats regarding the previous answer: 关于上一个答案的一些警告:

First: I see this error all the time. 第一:我一直看到这个错误。 When you provide an array element to "unset", you have to quote it. 当您提供“unset”数组元素时, 您必须引用它。 Consider: 考虑:

$ 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

What happened? 发生了什么? Globbing. 通配符。 You obviously wanted to delete element 2 of a[], but shell syntax being what it is, the shell first checked the current directory for a file that matched the glob pattern "a[2]". 你显然想要删除[]的元素2,但shell语法就是这样,shell首先检查当前目录中是否有与glob模式 “a [2]”匹配的文件。 If it finds a match, it replaces the glob pattern with that filename, and you wind up making a decision about which variable to delete based on what files exist in your current directory. 如果找到匹配项,它会用该文件名替换glob模式,最后根据当前目录中存在的文件决定删除哪个变量。

This is profoundly stupid. 这是非常愚蠢的。 But it's not something anyone has bothered to fix, apparently, and the error turns up in all kinds of documentation and example code from the last 3 decades. 但显然,这并不是任何人都不愿意解决的问题,并且在过去的三十年里,各种文档和示例代码中的错误都出现了。

Next is a related problem: it's easy to insert elements in your associative array with any key you like. 接下来是一个相关问题:使用您喜欢的任何键在关联数组中插入元素很容易。 But it's harder to remove these elements: 但是删除这些元素更难:

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

In bash you can do this: 在bash中你可以这样做:

unset -v "assoc[\$key]"

In Korn Shell, you have to do this: 在Korn Shell中,你必须这样做:

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

So it gets a bit more complicated in the case where your keys contain syntax characters. 因此,在密钥包含语法字符的情况下,它会变得更复杂一些。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM