Шаблон захватывает (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
— это просто метка, а окончательнаяta
t оценивает успешную замену и переходит обратно к a
, если замена была сделана, фактически повторяя процесс столько раз, как будто что-то делает. Следовательно, 1234567
превратится в 1,234,567
.
Вы можете черпать вдохновение из команд с похожим синтаксисом, таких как 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
(вы можете добавить другие имена, если хотите ). Если это не удается, вместо этого введите любое имя команды.