如何以交互方式在bash中输入n个数字的n个重复


20

我想运行命令

foo --bar=baz <16 zeroes>

如何有效输入16个零*?如果按住不放Alt1 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于历史中,而不是执行代码的结果。
Unbeliever

@meuh Alt本身不会发送任何字符,因此就所bash关注的情况而言,按下并释放alt不会产生任何效果。
斯特凡Chazelas

1
@Unbeliever做到我的意思,这会没事的

@Unbeliever:请看我的编辑,该段的要点history是我想输入数字而不使用命令替换。
JonasKölker'16

每当您希望自动为您键入内容时,AutoKey都是一个很棒的实用程序。使用它,您可以构建短语替换,或者完成Python宏,这些宏将在键入触发短语或按下热键时几乎完成您喜欢的任何事情。我之所以没有将其作为答案,是因为它需要GUI桌面环境,而其余答案则不需要-因此更通用。

Answers:


25

尝试

回声Alt+1Alt+6Ctrl+V0

这是6个键击(至少假设使用US / UK QWERTY键盘),以插入这16个零(可以同时按住Alt1和6)。

您也可以使用标准vi模式(set -o vi)并输入:

回声0 Escx16p

(还有6个按键)。

emacs等价的模式可以用于重复多个字符(),但不能在。echo 0Ctrl+WAlt+1Alt+6Ctrl+Yzshbash

所有这些都将适用于zsh(以及tcsh来自何处)。使用zsh,您还可以使用padding变量扩展标志,并使用以下命令进行扩展Tab

回声$ {(l:16 :: 0 :)}Tab

(显然,还有很多击键)。

有了bash,你也可以bash扩展您的$(printf '0%.0s' {1..16})使用Ctrl+Alt+E。请注意,虽然它将扩展行上的所有内容(但不是glob)。

要玩最少按键次数的游戏,可以将某个小部件绑定到某个按键,该小部件可以扩展<some-number>XX重复<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次击键)其中g16在底座36。

现在,我们可以将其进一步简化为一个插入这16个零的键,尽管那样会很欺骗。我们可以绑定F2到两个0s(或两个$STRING,默认情况下F3为0),三个0s,F1F6一个16 0s ...最多19个...当您定义任意窗口小部件时,可能性是无限的。

也许我应该提一下,如果您按住该0键,只需按一个键就可以插入任意多个零:-)


感谢您为vi和其他人提供多种变体!
马克·斯图尔特

9

假设您的终端仿真器不会占用按键(例如,切换选项卡)(纯xterm有效),则可以按Alt-1 6 Ctrl-V 0。此处需要使用control-V来分解数字和要重复的字符(如果您重复一个字母,则不需要它)。

(这是一个称为的readline功能digit-argument,因此您应该可以使用它bind来更改所涉及的修饰键)


1
谢谢,包括功能名称,在像我这样的人偶然发现这些问题时非常有用。相关链接,供您阅读:SO问题
打击

4

在Emacs中,通常C-q将前缀参数与数字输入区分开。

Bash使用Ctrl+v代替C-q,以避免XON / XOFF流控制出现问题。

这样就可以使用了Alt+1 Alt+6 Ctrl+v 0


3

另一个选择是键入四个零,然后使用鼠标将其复制并粘贴三遍。双击选择,单击鼠标中键x 3进行粘贴。


或通过键入一个 0 使其高尔夫/作弊更多,选择并粘贴以获得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键。(仍然是一个有用的简单功能)

^^^^^^^^^^^^^^^^^(base 36?Hah!):-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

这是获得16个零的6个键。

不更改任何键盘快捷键:

如果你坚持下去bash C-u kills the currently-being-typed line
那是因为"\C-u":绑定到unix-line-discard

但这也可能会有所帮助:
删除游标之前的时间时,还将其放置在“ kill-ring”中。

因此,ctrl+u擦除并ctrl+y撤回已擦除的内容。
在干净的行上:键入00擦除它,然后将其重新拉回两次以使其成为0000
重复以获得00000000(8个零),最后键入命令并再次拉回两次。

第一组(ctrl按住7键):

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-Y ctrl-A foo --bar = baz

那是11把钥匙


见我的回答;-)编辑
斯特凡Chazelas

@StéphaneChazelas使用宏吗?基地36?仅在zsh中?来吧...看我的编辑:-P
sorontar '16

好吧,base36有点像舌头。我喜欢您F<n>复制最后的单词<n>时间。
斯特凡Chazelas

请注意,并非所有终端都在F8上发送相同的序列(尽管在GNU / Linux系统上找到的大多数终端都发送^[[19~)。请参阅"$(tput kf8)"以从terminfo数据库(或中的$terminfo哈希zsh)获取信息。
斯特凡Chazelas

@StéphaneChazelas是的,是的。或直接使用ctrl-v F8
sorontar '16

2

作为cas答案的一种,请输入

printf'0%.s'{1..16}Enter
然后使用鼠标复制并粘贴(一次)。可以说这是O(log n),但是由于它是(len(str(n))+ 20),因此您可能认为它效率不高。但请注意:

  • 我能够刮掉一个字符-在我的系统上,%.s其行为似乎与相同%.0s
  • 如果要以0000000000000000参数作为参数运行多个命令,则只需执行一次。

格伦杰克曼指出的是 (其中,编号是正整数)将打印的字符串零(和换行符),如在格式星号告诉从参数采取字段宽度。具体来说,将打印16个零。但这是处理的特殊情况。  将打印,并且将打印 一条错误消息。相比之下,此答案中的其他命令将生成类似或 (的字符串,请参见下文printf "%0*d\n" number 0printfprintf "%0*d" 16 0 0printf "%0*d" 16 123450000000000012345printf "%0*d" 16 foo0000000000000000123451234512345…foofoofoo…7%7%7%...)。

如果要经常执行此操作,可以通过定义一个shell函数来简化它:

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})"


或者printf "%0*d" 16 0将打印16个零。格式中的星号将从参数中获取字段宽度
glenn jackman
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.