Как я могу вводить n повторений цифры в Bash, в интерактивном режиме

20

Я хотел бы запустить команду

foo --bar=baz <16 zeroes>

Как мне эффективно ввести 16 нулей *? Если я удерживаю Altи нажимаю, 1 6 0то повторю следующую вещь 160 раз, а это не то, чего я хочу. В emacs я могу использовать Alt-[number]или Ctrl-u 1 6 Ctrl-u 0, но в bash Ctrl-uубивает текущую набираемую строку, а следующий ноль просто добавляет 0 к строке.

Если я сделаю

foo --bar=baz $(printf '0%.0s' {1..16})

Тогда historyпоказывает именно выше, а не foo --bar=baz 0000000000000000; то есть bash не ведет себя так, как я хочу. ( Изменить : точка, я хочу ввести некоторое количество нулей без использования $(...)подстановки команд)

(*) Я предполагаю, что техническое определение «эффективно» - это «с O (log n) нажатий клавиш», предпочтительно количество нажатий клавиш, равное количеству цифр в 16 (для всех значений 16) плюс, возможно, константа; пример emacs квалифицируется как эффективный по этому определению.

Йонас Кёлкер
источник
1
Похоже, вы хотите, чтобы Bash просто так или иначе know what you want to do. В сложной вложенной команде как bash узнает, какие части вы хотите видеть в результате выполнения в истории, а не в самой команде? Как насчет переменных? Короче говоря, bash всегда будет иметь codeв истории, а не результат выполнения кода.
Неверующий
@meuh, Altсамо по себе не отправляет никаких символов, поэтому нажатие и отпускание alt не окажут никакого влияния на bashэто.
Стефан Шазелас
1
@ Unbeliever Делай, что я имею в виду, и все будет хорошо
кот
@Unbeliever: посмотрите мое редактирование - смысл параграфа в том, historyчто я хотел бы вводить цифры без использования подстановки команд.
Йонас Кёлкер
AutoKey - это отличная утилита, когда вы хотите, чтобы все печаталось автоматически. С его помощью вы можете создавать подстановки фраз или завершать макросы Python, которые будут делать практически все, что вам нравится, когда набирается триггерная фраза или нажата горячая клавиша. Я не включил это в качестве ответа, потому что для этого требуется среда рабочего стола с графическим интерфейсом, а остальные ответы - нет, и, следовательно, более применимы.
Джо

Ответы:

25

Пытаться

эхо Alt+1Alt+6Ctrl+V0

Это 6 нажатий клавиш (при условии, что клавиатура QWERTY в США и Великобритании установлена ​​минимум) для вставки этих 16 нулей (вы можете удерживать Altкак 1, так и 6).

Вы также можете использовать стандартный viрежим ( set -o vi) и введите:

эхо 0 Escx16p

(также 6 клавиш).

emacsЭквивалентный режим и который может быть использован для повторения более одного символа ( ) работает , но не в .echo 0Ctrl+WAlt+1Alt+6Ctrl+Yzshbash

Все они также будут работать zshtcshоткуда это). С помощью zshвы также можете использовать флаги расширения переменных заполнения и расширять их с помощью Tab:

echo $ {(l: 16 :: 0 :)}Tab

(Гораздо больше нажатий клавиш, очевидно).

С bash, вы также можете bashрасширить $(printf '0%.0s' {1..16})с Ctrl+Alt+E. Обратите внимание, что это расширит все (но не глобусы) в строке.

Чтобы играть в игру с наименьшим количеством нажатий клавиш, вы можете привязать к некоторому ключу виджет, который увеличивается <some-number>Xдо Xповторяющихся <some-number>времен. И есть <some-number>в базе 36, чтобы еще больше уменьшить его.

С zsh(связан F8):

repeat-string() {
  REPLY=
  repeat $1 REPLY+=$2
}
expand-repeat() {
  emulate -L zsh
  set -o rematchpcre
  local match mbegin mend MATCH MBEGIN MEND REPLY
  if [[ $LBUFFER =~ '^(.*?)([[:alnum:]]+)(.)$' ]]; then
    repeat-string $((36#$match[2])) $match[3]
    LBUFFER=$match[1]$REPLY
  else
    return 1
  fi
}
zle -N expand-repeat
bindkey "$terminfo[kf8]" expand-repeat

Затем для 16 нулей вы набираете:

эхо g0F8

(3 нажатия клавиш), где gнаходится 16в базе 36.

Теперь мы можем еще больше сократить его до одного ключа, который вставляет эти 16 нулей, хотя это будет обманом. Мы можем связать F2два 0с (или два $STRING, 0 по умолчанию), F3до 3 0с, F1F6до 16 0с ... до 19 ... возможности бесконечны, когда вы можете определить произвольные виджеты.

Возможно, я должен упомянуть, что если вы нажмете и удержите 0клавишу, вы можете вставить столько нулей, сколько захотите, всего одним нажатием клавиши :-)

Стефан Шазелас
источник
Спасибо за предоставление нескольких вариантов для viи других!
Марк Стюарт
9

Предполагая, что ваш эмулятор терминала не использует нажатие клавиш (например, для переключения вкладок) - работает xterm - вы можете нажать Alt-1 6 Ctrl-V 0. Контроль-V нужен там, чтобы разбить число и символ для повторения (если вы повторяли букву, вам это не понадобилось бы).

(Это функция readline, известная как digit-argument, так что вы должны иметь возможность использовать bindдля изменения используемых клавиш-модификаторов)

derobert
источник
1
Спасибо, в том числе название функции полезно, когда такие люди, как я, сталкиваются с этими вопросами. Ссылки по теме для более подробного чтения: SO Руководство по
admalledd
4

В Emacs я обычно использовал бы C-qдля отделения префиксного аргумента от ввода цифр.

Bash использует Ctrl+vвместо C-q, чтобы избежать проблем с управлением потоком XON / XOFF.

Так что вы можете использовать Alt+1 Alt+6 Ctrl+v 0.

Тоби Спейт
источник
3

Другой вариант - ввести четыре ноля, а затем с помощью мыши скопировать и вставить его еще три раза. дважды щелкните, чтобы выбрать, средний щелчок x 3, чтобы вставить.

саз
источник
Или сыграйте в гольф / обманите, набрав один ноль, выберите и вставьте, чтобы получить 2; выберите и вставьте это, чтобы получить 4; выберите и вставьте до 8, а затем снова до 16. Это воодушевляет :)
Джефф Шаллер
да, но набрав 4 ноля и повторив их вставку, мне кажется оптимальным уровень усилий против отдачи. все это дополнительное копирование и вставка кажутся работой.
Cas
3

Играя с макросами:

Привязать функциональную клавишу, F8чтобы умножить на два последние слова (до предыдущего пробела) (код клавиши F8, найденный с помощью Ctrl-V F8):

$ bind '"\e[19~": "\C-w\C-y\C-y"'

Это можно сделать постоянным, отправив тот же текст на ~/.inputrc

$ echo '"\e[19~": "\C-w\C-y\C-y"' >> ~/.inputrc

затем введите:

эхо 0F8F8F8F8

чтобы получить 2 ^ 4 раза больше нуля. (еще 5 нажатий клавиш).

или введите:

эхо книгаF8F8F8

чтобы получить 2 ^ 3 книжных слова.

Еще быстрее:

Умножьте на 4:

$ bind '"\e[19~": "\C-w\C-y\C-y\C-w\C-y\C-y"'

эхо 0F8F8

3 нажатия.

Умножьте на 8 (тот же номер, что и у функциональной клавиши)

$ bind '"\e[19~": "\C-w\C-y\C-y\C-w\C-y\C-y\C-w\C-y\C-y"'

эхо 00F8

Еще 3 клавиши.

Чит?

Обман, умножение на 16.

$ bind '"\e[19~": "\C-w\C-y\C-y\C-w\C-y\C-y\C-w\C-y\C-y\C-w\C-y\C-y"'

эхо 0F8

Всего 2 нажатия. (и все же полезная простая функция)

^^^^^^^^^^^^^^^^ (база 36? Ха!) :-P

Просто обманывает

$ bind '"\e[19~": "0000000000000000"'

эхо F8

Просто 1 (да: одно ) нажатие клавиши.



Изменение привязки для ctrl+U:

Отправить это по адресу ~/.inputrc:

echo '"\C-u": universal-argument >> ~/.inputrc

Перечитайте ~/.inputrcфайл:

ctrl+Xctrl+R

сделайте это как обычно в Emacs (как вы хотели):

foo --bar = baz ctrl+U16 ctrl+U0

7 клавиш (после «настройки»).

Немного короче:

Используйте значение по умолчанию «умножить на 4» для «универсального аргумента» и завершить

 ctrl+V 0 

foo --bar = baz ctrl+Uctrl+Uctrl+V0

Всего 5 ключей.

Использование alt+nдоступа к (arg: n)

foo --bar = baz Alt+16Ctrl+V0

Это 6 ключей, чтобы получить 16 нулей.

Не меняя сочетания клавиш:

Если в вашем bash у вас есть bash C-u kills the currently-being-typed line.
Это потому, что "\C-u":связано с unix-line-discard.

Но это также может помочь:
когда то, что находится перед удалением курсора, оно также помещается в «кольцо уничтожения».

Так ctrl+uстирает и ctrl+yвозвращает обратно то, что было стерто.
На чистой линии: 00напечатайте erase it и дважды потяните его назад, чтобы сделать это 0000.
Повторите, чтобы получить 00000000(8 нулей), наконец введите команду и дерните назад дважды.

Первый набор (7 клавиш удерживаются в ctrlнажатом состоянии):

00 ctrl+Uctrl+Yctrl+Y ctrl+U 

Второй набор (5 ключей)

ctrl+Uctrl+Yctrl+Y ctrl+U 

Это даст восемь нулей в стереть кольцо, затем введите то, что вы хотите:

 foo --bar = baz ctrl-Y ctrl-Y 

получить:

foo --bar=baz 0000000000000000

После того, как вы поймете идею, вы также можете набрать то, что вам нужно, перейти к началу строки ( ctrl-Y), сделать, как указано выше (до восьми нулей), перейти к концу ( ctrl-E) и дважды нажать.

foo --bar = baz ctrl-A00ctrl-Uctrl-Yctrl-Y ctrl-Uctrl-Yctrl-Y ctrl-U ctrl-Ectrl-Yctrl-Y

Это 15 клавиш (кроме самой команды).
Не коротко, я знаю, но это работает только с тем, что было доступно.

Это немного короче:

0000 ctrl-U ctrl-Y ctrl-Y ctrl-Y ctrl-Yctrl-A foo --bar = baz

Это 11 ключей

sorontar
источник
См. Редактирование моего ответа ;-)
Стефан Шазелас
@ StéphaneChazelas Используете макросы? База 36? Только в зш? Да ладно ... см. Мое редактирование :-P
sorontar
Ну да, base36 был немного языком в щеке. Мне нравится, что вы F<n>дублируете последнее слово <n>раз.
Стефан Шазелас,
Обратите внимание, что не все терминалы отправляют одну и ту же последовательность после F8 (хотя большинство из тех, что есть в системах GNU / Linux, отправляют ^[[19~). Смотрите, "$(tput kf8)"чтобы получить информацию из базы данных terminfo (или $terminfoхэша zsh).
Стефан Шазелас,
@ StéphaneChazelas Да, это правильно. Или просто использоватьctrl-v F8
Sorontar
2

В качестве варианта ответа cas введите

printf '0% .s' {1..16}Enter
а затем используйте мышь, чтобы скопировать и вставить его (один раз). Возможно, это O (log n), но, поскольку это (len (str (n)) + 20), вы можете считать его неэффективным. Но обратите внимание:

  • Мне удалось сбрить одного персонажа - в моей системе, %.sпохоже, ведет себя так же, как %.0s.
  • Если вы хотите запустить несколько команд 0000000000000000в качестве аргумента, вам нужно сделать это только один раз.

Glenn Джекман баллов из что (где число положительное целое число) будет печатать строку числа нулей (и перевод строки), как звездочка в формате говорит взять ширину поля из аргументов. В частности, будет напечатано 16 нулей. Но это особый случай, который обрабатывает только .  распечатает , а распечатает и сообщение об ошибке. Напротив, другие команды в этом ответе будут производить строки, подобные или (и см. Ниже для ).printf "%0*d\n" number 0printfprintf "%0*d" 16 0 0printf "%0*d" 16 123450000000000012345printf "%0*d" 16 foo0000000000000000123451234512345…foofoofoo…7%7%7%...

Если вы собираетесь делать это часто, вы можете упростить это, определив функцию оболочки:

rep() { printf -- "$1%.0s" $(seq 1 "$2"); printf "\n"; }

Примечания:

  • Используйте $(seq 1 "$2")вместо того, (1.."$2"}потому что последний не будет работать - посмотрите это , это , это и это . Обратите внимание, что некоторые ответы на эти вопросы предлагают использовать eval, но это, как правило, не рекомендуется.
  • Формат строки ( $1%.0s) должен быть в двойных кавычках (а не в одинарных), потому что он содержит параметр ( $1).
  • --Является защита от $1значений , начиная с -.
  • Вы можете получить аналогичную защиту, используя "%.0s$1"вместо "$1%.0s".
  • В любом случае, $1содержащее значение %вызовет удушье.
  • Если вам нужно , чтобы быть в состоянии обрабатывать $1значения , содержащие %, сделать

    rep() { local i; for ((i=0; i<$2; i++)); do printf '%s' "$1"; done; printf "\n"; }

Кроме того, как только вы определили такую ​​функцию, вы можете делать такие вещи, как

foo --bar=baz "$(rep 0 16)"

что немного меньше, чем печатать "$(printf '0%.0s' {1..16})".

G-Man говорит: «Восстанови Монику»
источник
Поочередно printf "%0*d" 16 0будет печатать 16 нулей. Звездочка в формате будет принимать ширину поля от аргументов
Гленн Джекман