Завершение zsh для sshpass

Шаблон захватывает (1 )начало строки или что-то, что не является ни цифрой, ни точкой, за которой следует (2 )любое количество цифр, по крайней мере одна, за которой следует (3 )ровно три цифры. Затем он помещает их обратно с запятой между (2 )и (3 ), фактически добавляя разделитель тысяч. Первая группа требуется только для того, чтобы не касаться дробных частей после запятой, так как мы не хотим, чтобы 1.2345превратилось в 1.2,345.

Обратите внимание, что шаблон написан в виде базовых регулярных выражений (BRE ), требующих обратной косой черты перед каждым ()и {}, чтобы сделать их особенными. Более того, для этого требуется GNU sed, где \+и \|также имеют особое значение в BRE как расширение . Команду лучше записать в виде расширенного регулярного выражения (sed -E, которое поддерживается многими реализациями sed ):

.

sed -E 's/(^|[^0-9.])([0-9]+)([0-9]{3})/\1\2,\3/g'

Кроме того, шаблон выполняет только одну замену, он не добавляет несколько тысяч разделителей к одному и тому же числу. /gв конце будет совпадать несколько раз в одной и той же строке, но уже замененные данные не обрабатываются. 1234567станет 1234,567, а не 1,234,567. Чтобы исправить это, нам нужно добавить цикл:

sed -E -e :a  -e 's/(^|[^0-9.])([0-9]+)([0-9]{3})/\1\2,\3/g' -e ta

Здесь :a— это просто метка, а окончательнаяtat оценивает успешную замену и переходит обратно к a, если замена была сделана, фактически повторяя процесс столько раз, как будто что-то делает. Следовательно, 1234567превратится в 1,234,567.

1
11.07.2020, 20:16
1 ответ

Вы можете черпать вдохновение из команд с похожим синтаксисом, таких как sudo, которая также принимает параметры, за которыми следует имя команды и ее параметры. См. также Динамическое автозаполнение zsh для пользовательских команд для ознакомления с написанием дополнений zsh.

Поместите следующий код в файл с именем _sshpassна вашем $fpath. (См. Как правильно сделать так, чтобы пользовательское завершение zsh «просто работало»? для более подробной информации о том, как zsh получает функции завершения.)

#compdef sshpass

_sshpass () {
  local context state line
  typeset -A opt_args

  _arguments \
    '(-d -e -f -p)-d+[read password from file descriptor]:file descriptor:_file_descriptors' \
    '(-d -e -f -p)-e[take password from $SSHPASS]' \
    '(-d -e -f -p)-f+[read password from file]:file:_files' \
    '(-d -e -f -p)-p+[actual password]::' \
    '(-)1:command:->command' \
    '*::arguments: _normal' \
    && return

  case $state in
    (command)
      if ((CURRENT == 2)); then
        # Insist that the first argument must be an option
        compadd -- -d -e -f -p
      else
        compadd ssh ||
        _command_names -e
      fi
      ;;
  esac
}

_sshpass "$@"

Краткое пояснение:

  • _argumentsупорядочивает завершение команды с опциями.
  • Опции -d, -e, -fи -pявляются взаимоисключающими. (-d -e -f -p)-d…определяет дополнения для -dи указывает, что это не должно предлагаться, если один из вариантов -d, -e, -fили -pуже присутствует.
  • -d+означает, что пробел между -dи его аргументом необязателен.
  • ->commandдля первого параметра заставляет _argumentsустановить для $stateзначение command, и выполнение продолжается ниже.
  • _normalдля аргументов после первого аргумента, отличного от -, приводит к их завершению, как если бы командная строка начиналась с первого аргумента, отличного от -. ::после *инструктирует zsh удалить опции из первого аргумента опции, отличной от -.
  • В качестве имени команды попробуйте ввести имя, переданное вcompadd(вы можете добавить другие имена, если хотите ). Если это не удается, вместо этого введите любое имя команды.
1
18.03.2021, 23:20

Теги

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