Como insiro n repetições de um dígito no bash, interativamente

20

Eu gostaria de executar o comando

foo --bar=baz <16 zeroes>

Como digito os 16 zeros com eficiência *? Se eu segurar Alte pressionar 1 6 0, repetirá a próxima coisa 160 vezes, o que não é o que eu quero. No emacs eu posso usar Alt-[number]or Ctrl-u 1 6 Ctrl-u 0, mas no bash Ctrl-umata a linha atualmente sendo digitada e o próximo zero apenas adiciona um 0 à linha.

Se eu fizer

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

Então historymostra exatamente o acima, e não foo --bar=baz 0000000000000000; ou seja, o bash não se comporta da maneira que eu quero. ( Edit : point being, quero inserir algum número de zeros sem usar a $(...)substituição de comandos)

(*) Acho que uma definição técnica de "eficientemente" é "com O (log n) pressionamentos de tecla", de preferência um número de pressionamentos de tecla igual ao número de dígitos em 16 (para todos os valores de 16) mais talvez uma constante; o exemplo emacs é qualificado como eficiente por esta definição.

Jonas Kölker
fonte
11
Parece que você quer o bash de alguma forma know what you want to do. Em um comando aninhado complexo, como o bash saberia quais partes você queria ver o resultado da execução no histórico em oposição ao próprio comando? E as variáveis? Em resumo, o bash sempre terá codeo histórico, não o resultado da execução do código.
Unbeliever
@meuh, Altpor si só, não envia nenhum personagem, então pressionar e liberar alt não terá nenhum efeito no que diz bashrespeito.
Stéphane Chazelas 10/10
11
@ Unbeliever Faça o que eu quero dizer e vai ficar tudo bem #
cat
@ Unbeliever: veja minha edição - o ponto do parágrafo relacionado a isso historyé que eu gostaria de inserir dígitos sem usar a substituição de comandos.
Jonas Kölker
Sempre que você deseja que as coisas sejam digitadas automaticamente, o AutoKey é um ótimo utilitário para usar. Com isso, você pode criar substituições de frases ou macros Python completas que farão quase o que quiser quando uma frase de gatilho for digitada ou pressionada uma tecla de atalho. Eu não incluí isso como resposta, porque requer um ambiente de área de trabalho da GUI e o restante das respostas não - e, portanto, é geralmente aplicável.
Joe

Respostas:

25

Experimentar

eco Alt+1Alt+6Ctrl+V0

São 6 toques de tecla (assumindo pelo menos um teclado QWERTY dos EUA / Reino Unido) para inserir esses 16 zeros (você pode pressionar Alt1 e 6).

Você também pode usar o vimodo padrão ( set -o vi) e digitar:

eco 0 Escx16p

(também 6 pressionamentos de tecla).

O emacsmodo equivalente e que poderia ser usado para repetir mais de um caractere ( ) funciona , mas não dentro .echo 0Ctrl+WAlt+1Alt+6Ctrl+Yzshbash

Todos eles também trabalharão com zsh(e de tcshonde isso vem). Com zsh, você também pode usar sinalizadores de expansão variável de preenchimento e expandi-los com Tab:

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

(Muito mais teclas, obviamente).

Com bash, você também pode bashexpandir o seu $(printf '0%.0s' {1..16})com Ctrl+Alt+E. Observe, porém, que ele expandirá tudo (mas não globs) na linha.

Para jogar o jogo com o menor número de toques de tecla, você pode vincular a alguma tecla um widget que se expanda <some-number>Xpara tempos Xrepetidos <some-number>. E tenha <some-number>na base 36 para reduzi-lo ainda mais.

Com zsh(vinculado a 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

Em seguida, para 16 zeros, você digita:

eco g0F8

(3 batidas de tecla), onde gé 16em base 36.

Agora podemos reduzi-lo ainda mais a uma chave que insere esses 16 zeros, embora isso seja trapaça. Poderíamos vincular F2a dois 0s (ou dois $STRING, 0 por padrão), F3a 3 0s, F1F6a 16 0s ... até 19 ... as possibilidades são infinitas quando você pode definir widgets arbitrários.

Talvez eu deva mencionar que, se você pressionar e segurar a 0tecla, poderá inserir quantos zeros quiser com apenas um toque de tecla :-)

Stéphane Chazelas
fonte
Obrigado por fornecer várias variações para vie outros!
Mark Stewart
9

Presumindo que o emulador de terminal não pressione a tecla (por exemplo, para alternar entre guias) - basta que o xterm funcione - você pode pressionar Alt-1 6 Ctrl-V 0. O controle-V é necessário para dividir o número e o caractere a repetir (se você estivesse repetindo uma letra, não precisaria).

(Esse é um recurso de linha de leitura conhecido como digit-argument, portanto, você poderá bindalterar as chaves modificadoras envolvidas)

derobert
fonte
11
Obrigado, incluir o nome do recurso é útil quando pessoas como eu tropeçam nessas perguntas. Links relacionados para um pouco mais de leitura: SO Question and bash manual
admalledd 10/10
4

No Emacs, eu normalmente usaria C-qpara separar o argumento do prefixo da entrada de dígitos.

O Bash usa, em Ctrl+vvez de C-q, para evitar problemas com o controle de fluxo XON / XOFF.

Então você pode usar Alt+1 Alt+6 Ctrl+v 0.

Toby Speight
fonte
3

outra opção é digitar quatro zeros e, em seguida, use o mouse para copiar e colar mais três vezes. clique duas vezes para selecionar, clique no meio x 3 para colar.

cas
fonte
Ou jogue golfe / trapaceie um pouco mais, digitando um zero, selecione e cole para obter 2; selecione e cole para obter 4; selecione & cole para 8 e novamente para 16. É POWerful :)
Jeff Schaller
Sim, mas digitar 4 zeros e repeti-los parece o nível ideal de esforço versus recompensa para mim. todas essas cópias e colagens extras parecem trabalho.
cas 11/11
3

Brincando com macros:

Ligue a tecla de função F8para multiplicar por duas a última palavra (no espaço anterior) (código da tecla F8 encontrado usando Ctrl-V F8):

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

Isso pode ser permanente enviando o mesmo texto para ~/.inputrc

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

então digite:

eco 0F8F8F8F8

para obter 2 ^ 4 vezes o zero. (ainda cinco pressionamentos de tecla).

ou digite:

livro de ecoF8F8F8

para obter 2 ^ 3 palavras no livro.

Ainda mais rápido:

Multiplique por 4:

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

eco 0F8F8

3 pressionamento de tecla.

Multiplique por 8 (o mesmo número da tecla de função)

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

eco 00F8

Ainda 3 pressionamentos de tecla.

Enganação?

Trapaça ao multiplicar por 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"'

eco 0F8

Apenas 2 teclas pressionadas. (e ainda uma função simples e útil)

^^^^^^^^^^^^^^^^ (base 36? Hah!) :-P

Claramente trapaceando:

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

eco F8

Apenas 1 (sim: um ) pressionamento de tecla.



Alterando a ligação para ctrl+U:

Envie para ~/.inputrc:

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

Releia o ~/.inputrcarquivo:

ctrl+Xctrl+R

faça como de costume no emacs (como você queria):

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

7 teclas (após a "configuração").

Um pouco mais curto:

Use o padrão "multiplique por 4" de "argumento universal" e termine com

 ctrl+V 0 0 

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

Apenas 5 chaves.

Usando o alt+nacesso a (arg: n)

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

São 6 chaves para obter os 16 zeros.

Não alterando nenhum atalho de teclado:

Se em sua festa você tem bash C-u kills the currently-being-typed line.
Isso é porque "\C-u":está vinculado unix-line-discard.

Mas isso também pode ajudar:
quando, o que é antes do cursor ser apagado, ele também é colocado no "anel de matança".

Então ctrl+uapaga e ctrl+ypuxa de volta o que foi apagado.
Em uma linha limpa: Digite 00apague-o e puxe-o novamente duas vezes para fazê-lo 0000.
Repita para obter 00000000(8 zeros), finalmente digite o comando e retroceda duas vezes.

O primeiro conjunto (7 teclas são mantidas ctrlpressionadas):

00 ctrl+Uctrl+Yctrl+Y ctrl+U 

O segundo conjunto (5 teclas)

ctrl+Uctrl+Yctrl+Y ctrl+U 

Isso receberá oito zeros no anel de apagamento e digite o que você deseja:

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

para obter:

foo --bar=baz 0000000000000000

Depois de ter a idéia, você também pode digitar o que precisa, ir para o início da linha ( ctrl-Y), fazer o acima (até oito zeros) até o final ( ctrl-E) e puxar duas vezes.

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

São 15 chaves (além do próprio comando).
Não é curto, eu sei, mas isso funciona apenas com o que estava disponível.

Isso é um pouco mais curto:

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

São 11 chaves

sorontar
fonte
Veja a edição da minha resposta ;-)
Stéphane Chazelas
@ StéphaneChazelas Usando macros? Base 36? Somente no zsh? Vamos lá ... veja minha edição :-P
sorontar 11/11
Bem, sim, a base36 era um pouco de língua na bochecha. Gosto de F<n>duplicar as últimas palavras <n>.
Stéphane Chazelas
Observe que nem todos os terminais enviam a mesma sequência no F8 (embora a maioria dos encontrados nos sistemas GNU / Linux envie ^[[19~). Consulte "$(tput kf8)"para obter as informações do banco de dados terminfo (ou do $terminfohash in zsh).
Stéphane Chazelas
@ StéphaneChazelas Sim, está correto. Ou simplesmente usarctrl-v F8
sorontar
2

Como uma variação da resposta de cas , digite

printf '0% .s' {1..16}Enter
e use o mouse para copiar e colar (uma vez). Indiscutivelmente, esse é O (log n), mas como é (len (str (n)) + 20), você pode considerá-lo ineficiente. Mas observe:

  • Consegui raspar um personagem - no meu sistema, %.sparece se comportar da mesma maneira que %.0s.
  • Se você quiser executar vários comandos 0000000000000000como argumento, faça isso apenas uma vez.

glenn jackman ressalta que (onde número é um número inteiro positivo) imprimirá uma sequência de números zeros (e uma nova linha), conforme o asterisco no formato diz para tirar a largura do campo dos argumentos. Especificamente, imprimirá 16 zeros. Mas este é um caso especial que lida apenas .  será impressa e será impressa e uma mensagem de erro. Por outro lado, os outros comandos nesta resposta produzirão seqüências de caracteres como or (e veja abaixo para ).printf "%0*d\n" number 0printfprintf "%0*d" 16 0 0printf "%0*d" 16 123450000000000012345printf "%0*d" 16 foo0000000000000000123451234512345…foofoofoo…7%7%7%...

Se você fizer isso com frequência, poderá simplificá-lo definindo uma função shell:

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

Notas:

  • Use em $(seq 1 "$2")vez de (1.."$2"}porque o último não funcionará - veja isto , isto , isto e isto . Observe que algumas das respostas para essas perguntas sugerem o uso eval, mas isso geralmente não é recomendado.
  • A string de formato ( $1%.0s) deve estar entre aspas duplas (em vez de aspas simples) porque contém um parâmetro ( $1).
  • O --é para proteger contra $1valores começando com -.
  • Você pode obter proteção semelhante usando em "%.0s$1"vez de "$1%.0s".
  • De qualquer maneira, um $1valor que contenha %fará com que ele se engasgue.
  • Se você precisar lidar com $1valores que contêm %, faça

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

Além disso, depois de definir essa função, você pode fazer coisas como

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

que é um pouco menos digitado que "$(printf '0%.0s' {1..16})".

G-Man Diz 'Reinstate Monica'
fonte
Como alternativa printf "%0*d" 16 0, imprimirá 16 zeros. O asterisco no formato terá a largura do campo a partir dos argumentos
Glenn Jackman