Comment saisir n répétitions d'un chiffre dans bash, de manière interactive

20

Je voudrais exécuter la commande

foo --bar=baz <16 zeroes>

Comment saisir efficacement les 16 zéros *? Si je maintiens la Alttouche enfoncée , 1 6 0cela répétera la prochaine chose 160 fois, ce qui n'est pas ce que je veux. Dans emacs, je peux utiliser Alt-[number]ou Ctrl-u 1 6 Ctrl-u 0, mais dans bash Ctrl-utue la ligne en cours de frappe et le zéro suivant ajoute simplement un 0 à la ligne.

Si je fais

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

Ensuite historymontre exactement ce qui précède, et non foo --bar=baz 0000000000000000; ie bash ne se comporte pas comme je le souhaite. ( Edit : point étant, je veux entrer un certain nombre de zéros sans utiliser la $(...)substitution de commande)

(*) Je suppose qu'une définition technique de "efficacement" est "avec O (log n) touches", de préférence un nombre de touches égal au nombre de chiffres en 16 (pour toutes les valeurs de 16) plus peut-être une constante; l'exemple emacs est considéré comme efficace par cette définition.

Jonas Kölker
la source
1
On dirait que vous voulez que bash soit juste en quelque sorte know what you want to do. Dans une commande imbriquée complexe, comment bash saurait-il quelles parties vous vouliez voir le résultat de l'exécution dans l'historique par opposition à la commande elle-même? Et les variables? En bref bash va toujours avoir le codedans l'historique, pas le résultat de l'exécution du code.
Incrédule du
@meuh, Alten soi, n'envoie aucun caractère, donc presser et relâcher alt n'aura aucun effet en ce qui bashconcerne.
Stéphane Chazelas
1
@Unbeliever Faites ce que je veux dire et ça ira
chat
@Unbeliever: voir ma modification - le point du paragraphe concernant historyétait que je voudrais entrer des chiffres sans utiliser la substitution de commande.
Jonas Kölker
Chaque fois que vous voulez que les choses soient tapées automatiquement pour vous, AutoKey est un excellent utilitaire à utiliser. Avec lui, vous pouvez créer des substitutions de phrases, ou compléter des macros Python qui feront presque tout ce que vous voulez quand une phrase de déclenchement est tapée ou qu'une touche de raccourci est pressée. Je n'ai pas inclus cela comme réponse car cela nécessite un environnement de bureau GUI et les autres réponses ne le font pas - et sont donc plus généralement applicables.
Joe

Réponses:

25

Essayer

écho Alt+1Alt+6Ctrl+V0

Cela représente 6 touches (en supposant un clavier QWERTY US / UK au moins) pour insérer ces 16 zéros (vous pouvez les maintenir Altpour 1 et 6).

Vous pouvez également utiliser le vimode standard ( set -o vi) et taper:

écho 0 Escx16p

(également 6 touches).

L' emacséquivalent de mode et qui pourrait être utilisé pour répéter plus d'un seul caractère ( ) fonctionne dans , mais pas dans .echo 0Ctrl+WAlt+1Alt+6Ctrl+Yzshbash

Tous ceux qui travailleront également avec zsh(et d' tcshoù cela vient). Avec zsh, vous pouvez également utiliser des indicateurs d'expansion de variable de remplissage et les développer avec Tab:

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

(Beaucoup plus de touches évidemment).

Avec bash, vous pouvez également bashdévelopper votre $(printf '0%.0s' {1..16})avec Ctrl+Alt+E. Notez cependant qu'il étendra tout (mais pas les globes) sur la ligne.

Pour jouer au jeu avec le moins de touches possibles, vous pouvez lier à une touche un widget qui se développe <some-number>Xà Xdes <some-number>moments répétés . Et ont <some-number>en base 36 pour le réduire encore plus.

Avec zsh(lié à 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

Ensuite, pour 16 zéros, vous tapez:

écho g0F8

(3 frappes) où gest 16en base 36.

Maintenant, nous pouvons encore le réduire à une clé qui insère ces 16 zéros, bien que ce serait de la triche. Nous pourrions lier F2à deux 0s (ou deux $STRING, 0 par défaut), F3à 3 0s, F1F6à 16 0s ... jusqu'à 19 ... les possibilités sont infinies lorsque vous pouvez définir des widgets arbitraires.

Je devrais peut-être mentionner que si vous maintenez la 0touche enfoncée, vous pouvez insérer autant de zéros que vous le souhaitez avec une seule touche :-)

Stéphane Chazelas
la source
Merci d'avoir fourni plusieurs variantes pour viet d'autres!
Mark Stewart
9

En supposant que votre émulateur de terminal ne mange pas la touche (par exemple, pour changer d'onglet) - xterm simple fonctionne - vous pouvez appuyer sur Alt-1 6 Ctrl-V 0. Le contrôle-V est nécessaire pour décomposer le nombre et le caractère à répéter (si vous répétiez une lettre, vous n'en auriez pas besoin).

(Il s'agit d'une fonction de ligne de lecture connue sous le nom de digit-argument, vous devriez donc pouvoir l'utiliser bindpour changer les touches de modification impliquées)

derobert
la source
1
Merci, y compris le nom de la fonctionnalité est utile lorsque des gens comme moi trébuchent sur ces questions. Liens connexes pour un peu plus de lecture: SO Question et manuel bash
admalledd
4

Dans Emacs, j'utilisais normalement C-qpour séparer l'argument préfixe de l'entrée numérique.

Bash utilise à la Ctrl+vplace de C-q, pour éviter les problèmes de contrôle de flux XON / XOFF.

Vous pouvez donc utiliser Alt+1 Alt+6 Ctrl+v 0.

Toby Speight
la source
3

une autre option consiste à taper quatre zéros, puis à utiliser la souris pour les copier et les coller trois fois de plus. double-cliquez pour sélectionner, cliquez avec le bouton central x 3 pour coller.

cas
la source
Ou jouer au golf / tricher un peu plus en tapant un zéro, sélectionnez et collez cela pour obtenir 2; sélectionnez et collez cela pour obtenir 4; sélectionner et coller à 8, et à nouveau pour 16. C'est PUISSANT :)
Jeff Schaller
oui, mais taper 4 zéros et les coller de façon répétée me semble le niveau d'effort optimal par rapport au résultat. tout ce copier-coller supplémentaire semble être du travail.
cas
3

Jouer avec des macros:

Liez la touche de fonction F8pour multiplier par deux le dernier mot (en haut de l'espace précédent) (code de touche F8 trouvé en utilisant Ctrl-V F8):

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

Cela pourrait être rendu permanent en envoyant le même texte à ~/.inputrc

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

puis tapez:

écho 0F8F8F8F8

pour obtenir 2 ^ 4 fois le zéro. (encore 5 touches).

ou tapez:

livre d'échoF8F8F8

pour obtenir 2 ^ 3 mots de livre.

Encore plus rapide:

Multipliez par 4:

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

écho 0F8F8

3 touches.

Multipliez par 8 (le même nombre que la touche de fonction)

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

écho 00F8

Encore 3 touches.

Tricher?

Trichez en multipliant par 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"'

écho 0F8

Seulement 2 touches. (et toujours une fonction simple utile)

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

Tricher clairement:

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

écho F8

Une seule touche (oui: une ).



Modification de la liaison pour ctrl+U:

Envoyez ceci à ~/.inputrc:

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

Relisez le ~/.inputrcfichier:

ctrl+Xctrl+R

faites-le comme d'habitude dans emacs (comme vous le vouliez):

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

7 touches (après la "mise en place").

Légèrement plus court:

Utilisez le "multiplier par 4" par défaut de "l'argument universel" et terminez par

 ctrl+V 0 

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

Seulement 5 clés.

Utilisation de l' alt+naccès à (arg: n)

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

C'est 6 clés pour obtenir les 16 zéros.

Ne modifier aucun raccourci clavier:

Si dans votre bash vous en avez bash C-u kills the currently-being-typed line.
C'est parce que "\C-u":c'est lié à unix-line-discard.

Mais cela pourrait aussi aider:
quand, ce qui est avant que le curseur ne soit effacé, il est également placé dans le "kill-ring".

Donc , ctrl+upermet d' effacer et ctrl+yYanks retour ce qui a été effacé.
Sur une ligne propre: tapez 00effacez-le et tirez-le deux fois pour le faire 0000.
Répétez l'opération pour obtenir 00000000(8 zéros), enfin tapez la commande et tirez deux fois en arrière.

Le premier jeu (7 touches ctrlmaintenues enfoncées):

00 ctrl+Uctrl+Yctrl+Y ctrl+U 

Le deuxième set (5 touches)

ctrl+Uctrl+Yctrl+Y ctrl+U 

Cela obtiendra huit zéros dans l'anneau d'effacement, puis tapez ce que vous voulez:

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

obtenir:

foo --bar=baz 0000000000000000

Après avoir compris l'idée, vous pouvez également taper ce dont vous avez besoin, aller au début de la ligne ( ctrl-Y), faire comme ci-dessus (jusqu'à huit zéros) aller à la fin ( ctrl-E) et tirer deux fois.

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

C'est 15 touches (à côté de la commande elle-même).
Pas court, je sais, mais cela ne fonctionne qu'avec ce qui était disponible.

C'est un peu plus court:

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

C'est 11 touches

Sorontar
la source
Voir le montage de ma réponse ;-)
Stéphane Chazelas
@ StéphaneChazelas Vous utilisez des macros? Base 36? Seulement en zsh? Allez ... voir mon montage :-P
sorontar
Et bien oui, le base36 était un peu ironique. J'aime votre F<n>duplication des derniers <n>temps de mot .
Stéphane Chazelas
Notez que tous les terminaux n'envoient pas la même séquence sur F8 (bien que la plupart de ceux trouvés sur les systèmes GNU / Linux envoient ^[[19~). Voir "$(tput kf8)"pour obtenir les informations de la base de données terminfo (ou du $terminfohachage zsh).
Stéphane Chazelas
@ StéphaneChazelas Oui, c'est exact. Ou utilisez simplementctrl-v F8
sorontar
2

Comme variante de la réponse de CAS , tapez

printf '0% .s' {1..16}Enter
puis utilisez la souris pour le copier et le coller (une fois). On peut dire que c'est O (log n), mais comme c'est (len (str (n)) + 20), vous pourriez le considérer comme inefficace. Mais notez:

  • J'ai pu raser un personnage - sur mon système, %.ssemble se comporter comme %.0s.
  • Si vous souhaitez exécuter plusieurs commandes avec 0000000000000000comme argument, vous devez le faire une seule fois.

glenn jackman souligne que (où nombre est un entier positif) imprimera une chaîne de zéros numériques (et une nouvelle ligne), comme l'astérisque dans le format indique de prendre la largeur du champ des arguments. Plus précisément, imprimera 16 zéros. Mais c'est un cas spécial qui ne gère que .  va imprimer , et va imprimer et un message d'erreur. En revanche, les autres commandes de cette réponse produiront des chaînes comme ou (et voir ci-dessous pour ).printf "%0*d\n" number 0printfprintf "%0*d" 16 0 0printf "%0*d" 16 123450000000000012345printf "%0*d" 16 foo0000000000000000123451234512345…foofoofoo…7%7%7%...

Si vous comptez le faire régulièrement, vous pouvez le rationaliser en définissant une fonction shell:

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

Remarques:

  • Utilisez $(seq 1 "$2")plutôt que (1.."$2"}parce que ce dernier ne fonctionnera pas - voyez ceci , ceci , ceci et ceci . Notez que certaines des réponses à ces questions suggèrent d'utiliser eval, mais ce n'est généralement pas recommandé.
  • La chaîne de format ( $1%.0s) doit être entre guillemets (plutôt que des guillemets simples) car elle contient un paramètre ( $1).
  • Il --s'agit de se protéger contre les $1valeurs commençant par -.
  • Vous pouvez obtenir une protection similaire en utilisant "%.0s$1"au lieu de "$1%.0s".
  • Dans les deux cas, une $1valeur contenant %provoquera son étranglement.
  • Si vous devez être capable de gérer des $1valeurs contenant %, faites

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

De plus, une fois qu'une telle fonction est définie, vous pouvez faire des choses comme

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

qui est un peu moins tapant que "$(printf '0%.0s' {1..16})".

G-Man dit «Réintègre Monica»
la source
Alternativement printf "%0*d" 16 0imprimera 16 zéros. L'astérisque dans le format prendra la largeur du champ des arguments
glenn jackman