Wie gebe ich interaktiv n Wiederholungen einer Ziffer in Bash ein?

20

Ich möchte den Befehl ausführen

foo --bar=baz <16 zeroes>

Wie schreibe ich die 16 Nullen effizient *? Wenn ich gedrückt halte Altund drücke 1 6 0, wird es das nächste Mal 160 Mal wiederholt, was ich nicht will. In Emacs kann ich entweder Alt-[number]oder verwenden Ctrl-u 1 6 Ctrl-u 0, aber in bash wird Ctrl-udie aktuell eingegebene Zeile beendet, und die nächste Null fügt der Zeile nur eine 0 hinzu.

Wenn ich mache

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

Dann historyzeigt genau das oben, und nicht foo --bar=baz 0000000000000000; Bash verhält sich also nicht so, wie ich es will. ( Edit : point being, ich möchte eine Anzahl von Nullen eingeben, ohne die $(...)Befehlssubstitution zu verwenden)

(*) Ich denke, eine technische Definition von "effizient" ist "mit O (log n) Tastenanschlägen", vorzugsweise eine Anzahl von Tastenanschlägen, die der Anzahl von Ziffern in 16 (für alle Werte von 16) plus vielleicht einer Konstanten entspricht; Das Emacs-Beispiel wird durch diese Definition als effizient eingestuft.

Jonas Kölker
quelle
1
Klingt wie Sie wollen, dass Bash nur irgendwie know what you want to do. Woher weiß Bash in einem komplexen verschachtelten Befehl, welche Teile Sie das Ergebnis der Ausführung im Verlauf sehen möchten, im Gegensatz zum Befehl selbst? Was ist mit Variablen? Kurz gesagt, Bash wird immer das codein der Geschichte haben, nicht das Ergebnis der Ausführung des Codes.
Ungläubiger
@meuh Altsendet an sich kein Zeichen, daher hat das Drücken und Loslassen von alt keine Auswirkung bash.
Stéphane Chazelas
1
@Unbeliever Do What I Mean und es wird okay sein
Katze
@Unbeliever: siehe meine Bearbeitung - der Punkt des Absatzes, der damit zu tun hatte, historywar, dass ich Ziffern eingeben möchte, ohne die Befehlsersetzung zu verwenden.
Jonas Kölker
Wann immer Sie möchten, dass Dinge automatisch für Sie eingegeben werden, ist AutoKey ein großartiges Dienstprogramm. Mit ihm können Sie Phrasenersetzungen erstellen oder Python-Makros vervollständigen, die fast alles tun, was Sie möchten, wenn eine Triggerphrase eingegeben oder ein Hotkey gedrückt wird. Ich habe dies nicht als Antwort aufgenommen, da eine GUI-Desktop-Umgebung erforderlich ist und die übrigen Antworten dies nicht tun - und daher allgemeiner anwendbar sind.
Joe

Antworten:

25

Versuchen

Echo Alt+1Alt+6Ctrl+V0

Das sind 6 Tastenanschläge (vorausgesetzt eine US / UK QWERTY-Tastatur mindestens), um diese 16 Nullen einzufügen (Sie können halten) Alt sowohl 1 als auch 6 halten).

Sie können auch den Standardmodus vi( set -o vi) verwenden und Folgendes eingeben:

Echo 0 Escx 16p

(auch 6 Tastenanschläge).

Der emacsäquivalente Modus, der verwendet werden könnte, um mehr als ein einzelnes Zeichen ( ) zu wiederholen, funktioniert in , aber nicht in .echo 0Ctrl+WAlt+1Alt+6Ctrl+Yzshbash

Alle werden auch damit arbeiten zsh(und tcshwoher das kommt). Mit zshkönnen Sie auch Füllvariablen-Erweiterungsflags verwenden und diese erweitern mit Tab:

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

(Offensichtlich viel mehr Tastenanschläge).

Mit bashkönnen Sie auch bashIhre $(printf '0%.0s' {1..16})mit erweitern Ctrl+Alt+E. Beachten Sie jedoch, dass es alles (aber keine Globs) in der Zeile erweitert.

Um das Spiel mit der geringsten Anzahl von Tastenanschlägen zu spielen, können Sie ein Widget, das <some-number>Xsich Xmehrmals wiederholt , an eine Taste binden <some-number>. Und haben <some-number>in Basis 36, um es noch weiter zu reduzieren.

Mit zsh(gebunden an 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

Dann geben Sie für 16 Nullen Folgendes ein:

echo g0F8

(3 Tastenanschläge), wo gsich 16in Basis 36 befindet.

Jetzt können wir es weiter auf einen Schlüssel reduzieren, der diese 16 Nullen einfügt, obwohl das schummeln würde. Wir könnten F2an zwei 0s (oder zwei $STRING, standardmäßig 0), F3an 3 0s und F1F6an 16 binden0 s ... bis zu 19 ... Möglichkeiten sind endlos, wenn Sie beliebige Widgets definieren können.

Vielleicht sollte ich erwähnen, dass Sie, wenn Sie die 0Taste gedrückt halten , mit nur einem Tastendruck so viele Nullen einfügen können, wie Sie möchten :-)

Stéphane Chazelas
quelle
Vielen Dank für die Bereitstellung mehrerer Variationen für viund andere!
Mark Stewart
9

Angenommen, Ihr Terminal-Emulator nimmt den Tastenanschlag nicht wahr (z. B. um zwischen Registerkarten zu wechseln) Alt-1 6 Ctrl-V 0. Das Kontroll-V wird benötigt, um die Zahl und das zu wiederholende Zeichen aufzuteilen (wenn Sie einen Buchstaben wiederholen würden, würden Sie ihn nicht brauchen).

(Dies ist eine Readline-Funktion, die als bekannt digit-argumentist. Sie sollten also in der Lage sein, binddie beteiligten Modifikatortasten zu ändern.)

derobert
quelle
1
Vielen Dank, auch der Name der Funktion ist nützlich, wenn Leute wie ich über diese Fragen stolpern. Weiterführende Links zum Lesen: SO Question and bash manual
admalledd
4

In Emacs würde ich normalerweise verwenden C-q, um das Präfixargument von der Zifferneingabe zu trennen.

Bash verwendet Ctrl+vstatt C-q, um Probleme mit der XON / XOFF-Flusssteuerung zu vermeiden.

So können Sie verwenden Alt+1 Alt+6 Ctrl+v 0.

Toby Speight
quelle
3

Eine andere Möglichkeit besteht darin, vier Nullen einzugeben und diese dann noch dreimal mit der Maus zu kopieren und einzufügen. Doppelklicken Sie zum Auswählen, und klicken Sie zum Einfügen mit der mittleren Maustaste auf x 3.

cas
quelle
Oder spielen Sie Golf / betrügen Sie noch etwas, indem Sie eine Null eingeben . Wählen und einfügen, um 2 zu erhalten. wähle & füge das ein, um 4 zu erhalten; wähle & füge es auf 8 und für 16 wieder ein. Es ist POWerful :)
Jeff Schaller
Ja, aber die Eingabe von 4 Nullen und das wiederholte Einfügen scheint mir das optimale Maß an Aufwand im Vergleich zur Auszahlung zu sein. all das zusätzliche Kopieren und Einfügen scheint Arbeit zu sein.
cas
3

Mit Makros spielen:

Binden Sie die Funktionstaste F8, um das letzte Wort (bis zum vorherigen Leerzeichen) mit zwei zu multiplizieren (F8-Tastencode gefunden mit Ctrl-V F8):

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

Dies könnte dauerhaft gemacht werden, indem derselbe Text an gesendet wird ~/.inputrc

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

dann tippe:

Echo 0F8F8F8F8

2 ^ 4 mal die Null zu bekommen. (noch 5 Tastenanschläge).

oder Typ:

Echo-BuchF8F8F8

2 ^ 3 Buchwörter zu bekommen.

Noch schneller:

Mit 4 multiplizieren:

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

Echo 0F8F8

3 Tastendruck.

Mit 8 multiplizieren (die gleiche Zahl wie die Funktionstaste)

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

echo 00F8

Noch 3 Tastendrücke.

Betrügen?

Cheat durch Multiplikation mit 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"'

Echo 0F8

Nur 2 Tastendruck. (und immer noch eine nützliche einfache Funktion)

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

Betrügt einfach:

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

Echo F8

Nur 1 (ja: 1 ) Tastendruck.



Ändern der Bindung für ctrl+U:

Senden Sie dies an ~/.inputrc:

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

Lesen Sie die ~/.inputrcDatei erneut:

ctrl+Xctrl+R

mach es wie es in emacs üblich ist (wie du wolltest):

foo - bar = baz ctrl+U16 ctrl+U0

7 Tasten (nach dem "Einrichten").

Etwas kürzer:

Verwenden Sie die Standardeinstellung "Multiplizieren mit 4" für "Universalargument" und enden Sie mit

 ctrl+V 0 

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

Nur 5 Schlüssel.

Verwendung des alt+nZugriffs auf (arg: n)

foo - bar = baz Alt+16Ctrl+V0

Das sind 6 Schlüssel, um die 16 Nullen zu erhalten.

Keine Tastenkombination ändern:

Wenn Sie in Ihrer Bash haben bash C-u kills the currently-being-typed line.
Das liegt daran, "\C-u":ist binden an unix-line-discard.

Das könnte aber auch helfen:
Wenn, was ist, bevor der Cursor gelöscht wird, wird es auch in den "Kill-Ring" gelegt.

Also ctrl+ulöscht und ctrl+yreißt zurück, was gelöscht wurde.
In einer sauberen Linie: 00Geben Sie Erase It ein und ziehen Sie es zweimal zurück, um es zu erstellen 0000.
Wiederholen Sie dies, um 00000000(8 Nullen) zu erhalten, geben Sie schließlich den Befehl ein und ziehen Sie ihn zweimal zurück.

Der erste Satz (7 Tasten ctrlgedrückt halten ):

00 ctrl+Uctrl+Yctrl+Y ctrl+U 

Der zweite Satz (5 Schlüssel)

ctrl+Uctrl+Yctrl+Y ctrl+U 

Das wird acht Nullen im Löschring bekommen, dann tippe was du willst:

 foo - bar = baz ctrl-Y ctrl-Y 

bekommen:

foo --bar=baz 0000000000000000

Wenn Sie auf die Idee gekommen sind, können Sie auch eingeben , was Sie brauchen, zum Anfang der Zeile gehen ( ctrl-Y), wie oben beschrieben ctrl-Evorgehen (bis zu acht Nullen), bis zum Ende gehen ( ) und zweimal ziehen.

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

Das sind 15 Tasten (neben dem Befehl selbst).
Nicht kurz, ich weiß, aber das funktioniert nur mit dem, was verfügbar war.

Das ist etwas kürzer:

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

Das sind 11 Schlüssel

Sorontar
quelle
Siehe Bearbeitung meiner Antwort ;-)
Stéphane Chazelas
@ StéphaneChazelas Makros verwenden? Basis 36? Nur in zsh? Komm schon ... siehe meine Bearbeitung :-P
sorontar
Na ja, der base36 war ein bisschen frech. Ich mag es, F<n>wenn du das letzte Wort <n>mal duplizierst .
Stéphane Chazelas
Beachten Sie, dass nicht alle Terminals die gleiche Sequenz mit F8 senden (obwohl die meisten der GNU / Linux-Systeme senden ^[[19~). Siehe "$(tput kf8)", um die Informationen aus der terminfo-Datenbank (oder dem $terminfoHash-In zsh) abzurufen .
Stéphane Chazelas
@ StéphaneChazelas Ja, das stimmt. Oder verwenden Sie einfachctrl-v F8
sorontar
2

Als Variation der Antwort von cas , Typ

printf '0% .s' {1..16}Enter
und dann mit der Maus kopieren und einfügen (einmal). Möglicherweise ist dies O (log n), aber da es (len (str (n)) + 20) ist, können Sie es als ineffizient betrachten. Aber beachten Sie:

  • Ich konnte einen Charakter abschneiden - auf meinem System %.sscheint sich das genauso zu verhalten wie %.0s.
  • Wenn Sie mehrere Befehle 0000000000000000als Argument ausführen möchten , müssen Sie dies nur einmal tun.

Glenn jackman weist darauf hin , dass (wo Anzahl eine positive ganze Zahl) wird eine Zeichenfolge von Druck Anzahl Nullen (und einem Zeilenvorschub), wie das Sternchen in dem Format zeigt die Feldbreite von den Argumenten zu nehmen. Insbesondere werden 16 Nullen gedruckt. Dies ist jedoch ein Sonderfall, der nur behandelt wird .  wird gedruckt , und wird gedruckt und eine Fehlermeldung. Im Gegensatz dazu erzeugen die anderen Befehle in dieser Antwort Zeichenfolgen wie oder (und siehe unten für ).printf "%0*d\n" number 0printfprintf "%0*d" 16 0 0printf "%0*d" 16 123450000000000012345printf "%0*d" 16 foo0000000000000000123451234512345…foofoofoo…7%7%7%...

Wenn Sie dies häufig tun, können Sie es optimieren, indem Sie eine Shell-Funktion definieren:

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

Anmerkungen:

  • Verwenden Sie $(seq 1 "$2")anstelle von, (1.."$2"}weil Letzteres nicht funktioniert - sehen Sie dies , dies , dies und das . Beachten Sie, dass einige der Antworten auf diese Fragen die Verwendung von evalempfehlen, dies wird jedoch im Allgemeinen nicht empfohlen.
  • Die Formatzeichenfolge ( $1%.0s) muss in doppelten Anführungszeichen (und nicht in einfachen Anführungszeichen) angegeben werden, da sie einen Parameter ( $1) enthält.
  • Das --soll vor $1Werten schützen , die mit beginnen -.
  • Sie könnten einen ähnlichen Schutz erhalten, wenn Sie "%.0s$1"anstelle von verwenden "$1%.0s".
  • In beiden Fällen führt ein $1Wert, der enthält, %dazu, dass er erstickt.
  • Wenn Sie in der Lage sein müssen, mit $1Werten umzugehen %, die Folgendes enthalten :

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

Sobald Sie eine solche Funktion definiert haben, können Sie auch Dinge tun wie

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

Das ist etwas weniger tippen als "$(printf '0%.0s' {1..16})".

G-Man sagt, "Monica wiedereinsetzen"
quelle
Alternativ printf "%0*d" 16 0werden 16 Nullen ausgegeben. Das Sternchen im Format nimmt die
Feldbreite