6

ksh で使用するカスタマイズされた .profile があります。以下は、非常に複雑な名前または長い名前のディレクトリを前後にスキップするために作成した関数です。

ご覧のとおり、パス名は配列 ( 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
}
4

3 に答える 3

5

Kornシェル(およびBashなど)の配列はスパースであるためunset、配列のメンバーを削除するために使用する場合、配列のサイズを最後のメンバーのインデックスとして使用することはできません。その他の制限もあります。

ここにいくつかの便利なスニペットがあります(2番目の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を前提としていますが、以前のバージョンでは機能しない場合があります。

于 2010-01-21T05:23:37.283 に答える
2

unset を使用できます。たとえば、配列要素 1 を削除するには

unset array[0]

配列全体を削除するには

unset array
于 2010-01-21T00:22:44.073 に答える
1

前の回答に関するいくつかの注意事項:

最初: このエラーは常に表示されます。配列要素を「設定解除」する場合は、引用符で囲む必要があります。 検討:

$ 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 を削除したかったのですが、シェルの構文がそのままであるため、シェルは最初に現在のディレクトリでグロブ パターン「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 シェルでは、これを行う必要があります。

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

そのため、キーに構文文字が含まれている場合は、もう少し複雑になります。

于 2016-08-29T18:34:52.197 に答える