Как в ZSH удалить произвольный элемент ассоциативного массива?

Создайте для него новый MIME-тип. Сначала создайте файл text-rkt.xmlс содержимым :

.
<?xml version="1.0" encoding="UTF-8"?>
<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>
    <mime-type type="text/rkt">
        <comment>rkt text</comment>
        <generic-icon name="leafpad"/>
        <glob pattern="*.rkt"/>
    </mime-type>
</mime-info>

Затем добавьте это в локальную базу данных MIME:

xdg-mime install text-rkt.xml

Затем свяжите с какой-нибудь программой (, например. листовая пластинка):

xdg-mime default leafpad.desktop text/rkt

И вуаля :все файлы.rkt будут открываться в leafpad. (и их иконка тоже листовая)

3
29.12.2020, 00:56
1 ответ

Ух ты, какой бардак.

Поскольку патч 2016 года Барта Шефера , объединенный как патч 37914 в коммите 95663e936596933d529a648ed3d6c707d1a1dffe и впервые выпущенный в zsh 5.4, экспериментально, unset "arr[$key]"работает до тех пор, пока keyне работает содержать любой из следующих символов:\`()[]. Эти шесть символов должны начинаться с обратной косой черты, а другие символы не должны иметь (, например, unset 'arr[\*] arr[\;]'пытается сбросить ключи \*и \;, а не *и;). Это не то, что делает любой из цитирующих флагов раскрытия параметра (${(b)key}, ${(q)key}и его вариантов ).

Кроме того, есть дополнительная проблема. :Я не могу найти способ сбросить пустой ключ. unset 'arr[]'является ошибкой, и все остальное приводит к сбросу не -пустого ключа. Единственный обходной путь, который я нашел для сброса пустого ключа, — это переназначить массив полностью, используя флаг нижнего индекса для фильтрации нежелательных ключей (, как это было предложено Стефаном Шазеласом в 2018 г. zsh -рабочая нить).

Следующая функция работает в zsh ≥5.4 (протестирована в zsh 5.8 )и копирует массив только в том случае, если необходимо удалить пустой ключ.

# Usage: unset_keys ARRAY [KEY]...
# ARRAY must be the name of an associative array parameter.
# Equivalent to unset 'ARRAY[KEY1]' 'ARRAY[KEY2]'...
# except that this function works correctly even with keys containing
# special characters or is empty. See
# https://unix.stackexchange.com/questions/626393/in-zsh-how-do-i-unset-an-arbitrary-associative-array-element
function unset_keys {
  emulate -LR zsh
  if [[ -${(Pt)1}- != *-association-* ]]; then
    return 120 # Fail early if $1 is not the name of an associative array
  fi
  if ((${#@[2,$#]:#?*})); then
    if [[ -n ${${(P)1}[${:-}]+y} ]]; then
      # Copy all entries with non-empty keys
      : "${(AAP)1::=${(@kv)${(P)1}[(I)?*]}}"
    fi
    set -- $@ # Remove empty keys from the to-do list
  fi
  if (($# < 2)); then
    return 0
  fi
  set -- "$1" "${@[2,$#]//\\/\\\\}"
  set -- "$1" "${@[2,$#]//\`/\\\`}"
  set -- "$1" "${@[2,$#]//\(/\\(}"
  set -- "$1" "${@[2,$#]//\)/\\)}"
  set -- "$1" "${@[2,$#]//\[/\\[}"
  set -- "$1" "${@[2,$#]//\]/\\]}"
  noglob unset $1[${^@[2,$#]}]
}

Вот более простая функция, которая просто делает одну копию, несмотря ни на что.

# Usage: unset_keys ARRAY [KEY]...
# ARRAY must be the name of an associative array parameter.
# Equivalent to unset 'ARRAY[KEY1]' 'ARRAY[KEY2]'...
# except that this function works correctly even with keys containing
# special characters or is empty. See
# https://unix.stackexchange.com/questions/626393/in-zsh-how-do-i-unset-an-arbitrary-associative-array-element
function unset_keys {
  emulate -LR zsh
  setopt extended_glob
  if [[ -${(Pt)1}- != *-association-* ]]; then
    return 120 # Fail early if $1 is not the name of an associative array
  fi
  set -- "$1" "${(j:|:)${(@b)@[2,$#]}}"
  # Copy all entries except the specified ones
  : "${(AAP)1::=${(@kv)${(P)1}[(I)^($~2)]}}"
}

До zsh 5.4 это был другой беспорядок, который я не исследовал.


Вот испытательный комплект, который я использовал. Я думаю, что это дает разумное покрытие, но я не тратил время на его полировку.

set -e

test_keys=(
  '()safe' '(r)set' '(R)set' '(k)safe' # look like valid subscript flags
  '(a' '(a)' '(n:foo:)a' '(n:1)a' # look like invalid subscript flags
  'set' '"set"' \'set\' '\s\e\t'
  'safe' '"safe"' \'safe\' '\s\a\f\e'
  '\\' '\\\' '\\\\' '""' \'\'
  'two words' 'two  spaces' ' initial space' 'trailing space '
  $'\x80\\' $'\x80\`' $'\x80\~' # broken UTF-8
  ''
  '?~>#'
)
for ((i=0; i<255; i++)); do
  printf -v n '\\x%02x' $i
  eval "test_keys+=(\$'$n')"
done

function populate_test_array {
  for k in "${(@)test_keys}"; do
    arr[$k]=set
  done
}

function check_expected_keys {
  local -a actual_keys
  actual_keys=("${(@k)arr}")
  actual_keys=("${(@o)actual_keys}") # Sorting in one step seems to misplace the empty string at the end (zsh 5.8 on Ubuntu 20.04), so sort in two steps.
  local actual_list="${(j: :)${(@qqqq)actual_keys}}"
  local expected_list="${(j: :)${(@qqqq)expected_keys}}"
  if [[ "$actual_list" != "$expected_list" ]]; then
    <<EOF
Failure: unexpected list of keys after $1
  expected: $expected_list
  actual  : $actual_list
EOF
    ((++errors))
  fi
}

typeset -A arr
errors=0

populate_test_array
expected_keys=("${(@o)test_keys}")
test_keys=("${(@)test_keys:#safe}") # [safe] must stay until the end
for k in "${(@)test_keys}"; do
  unset_keys arr "$k"
  if (($+arr[$k])); then
    printf 'Failure: unset %s did not unset it\n' "${(qq)k}"
    ((++errors))
  else
    expected_keys=("${(@)expected_keys:#"$k"}")
  fi
  check_expected_keys "unset ${(qq)k}"
done

populate_test_array
unset_keys arr "${(@)test_keys}"
expected_keys=(safe)
check_expected_keys "unsetting all"

exit $((!!errors))
7
18.03.2021, 22:40

Теги

Похожие вопросы