Jak wpisać n powtórzeń cyfry w bashu, interaktywnie

20

Chciałbym uruchomić polecenie

foo --bar=baz <16 zeroes>

Jak efektywnie wpisać 16 zer *? Jeśli przytrzymam Alti wcisnę 1 6 0, powtórzy to 160 razy, co nie jest tym, czego chcę. W emacsie mogę użyć Alt-[number]albo Ctrl-u 1 6 Ctrl-u 0, ale w bash Ctrl-uzabija aktualnie pisaną linię, a następne zero po prostu dodaje 0 do linii.

Jeśli zrobię

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

Następnie historypokazuje dokładnie powyższe, a nie foo --bar=baz 0000000000000000; tzn. bash nie zachowuje się tak, jak chcę. ( Edytuj : wskazując na to, że chcę wprowadzić pewną liczbę zer bez użycia $(...)podstawiania poleceń)

(*) Wydaje mi się, że techniczną definicją „wydajnie” jest „z klawiszami O (log n)”, najlepiej liczbą klawiszy równą liczbie cyfr w 16 (dla wszystkich wartości 16) plus być może stałą; przykład emacsa kwalifikuje się jako wydajny na podstawie tej definicji.

Jonas Kölker
źródło
1
Wygląda na to, że po prostu chcesz bash know what you want to do. W złożonym zagnieżdżonym poleceniu, skąd miałbyś wiedzieć, które części chcesz zobaczyć wynik wykonania w historii, a nie samo polecenie? Co ze zmiennymi? Krótko mówiąc, zawsze będzie to miało miejsce codew historii, a nie wynik działania kodu.
niewierzący
@meuh, Altsam w sobie nie wysyła żadnej postaci, więc naciśnięcie i zwolnienie klawisza Alt nie będzie miało żadnego efektu, jeśli chodzi o bashto.
Stéphane Chazelas,
1
@ Unbeliever Rób co mam na myśli, a będzie OK
kot
@ Unbeliever: patrz moja edycja - chodzi o historyto, że chciałbym wprowadzić cyfry bez zastępowania poleceń.
Jonas Kölker,
Ilekroć chcesz, aby rzeczy były wpisywane automatycznie, AutoKey jest doskonałym narzędziem do użycia. Dzięki niemu możesz budować podstawienia fraz lub wypełniać makra Pythona, które zrobią wszystko, co chcesz, po wpisaniu frazy wyzwalającej lub naciśnięciu klawisza skrótu. Nie podałem tego jako odpowiedzi, ponieważ wymaga środowiska graficznego z graficznym interfejsem użytkownika, a pozostałe odpowiedzi nie - i dlatego mają bardziej ogólne zastosowanie.
Joe

Odpowiedzi:

25

Próbować

echo Alt+1Alt+6Ctrl+V0

To 6 uderzeń klawisza (przy założeniu co najmniej klawiatury QWERTY w USA / Wielkiej Brytanii), aby wstawić te 16 zer (możesz przytrzymać Altzarówno dla 1, jak i 6).

Możesz także użyć vitrybu standardowego ( set -o vi) i wpisać:

echo 0 Escx16p

(także 6 klawiszy).

emacsRównoważny sposób i które mogłyby być wykorzystane, aby powtórzyć więcej niż jednego znaku ( ) działa , ale nie w .echo 0Ctrl+WAlt+1Alt+6Ctrl+Yzshbash

Wszystkie te będą również współpracować zsh(i tcshskąd to pochodzi). Za pomocą zshmożna również użyć dopełniających zmiennych zmiennych rozszerzania i rozwinąć je za pomocą Tab:

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

(Oczywiście o wiele więcej naciśnięć klawiszy).

Za pomocą bashmożesz także bashrozszerzyć swoją ofertę $(printf '0%.0s' {1..16})o Ctrl+Alt+E. Zauważ jednak, że rozwinie on wszystko (nie globusy) na linii.

Aby zagrać w grę z najmniejszą liczbą naciśnięć klawiszy, możesz powiązać z jednym klawiszem widżet, który rozwija się <some-number>Xdo Xpowtarzanych <some-number>czasów. I mieć <some-number>w bazie 36, aby jeszcze bardziej ją zmniejszyć.

Z zsh(związany z 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

Następnie dla 16 zer wpisujesz:

echo g0F8

(3 klawiszy), w którym gznajduje się 16w podstawie 36.

Teraz możemy jeszcze bardziej zredukować go do jednego klucza, który wstawia te 16 zer, choć byłoby to oszustwem. Możemy powiązać F2dwa 0s (lub dwa $STRING, domyślnie 0), F33 0s, F1F616 0s ... do 19 ... możliwości są nieograniczone, kiedy można zdefiniować dowolne widżety.

Może powinienem wspomnieć, że jeśli naciśniesz i przytrzymasz 0klawisz, możesz wstawić tyle zer, ile chcesz za jednym naciśnięciem klawisza :-)

Stéphane Chazelas
źródło
Dziękujemy za udostępnienie wielu odmian dla vii innych!
Mark Stewart,
9

Zakładając, że emulator terminalu nie zjada naciśnięcia klawisza (np. Przełączanie kart) - działa xterm - możesz nacisnąć Alt-1 6 Ctrl-V 0. Kontrolne V jest tam potrzebne, aby rozbić liczbę i znak, aby powtórzyć (jeśli powtarzałeś literę, nie byłbyś potrzebny).

(Jest to funkcja readline znana jako digit-argument, więc powinieneś być w stanie bindzmienić zaangażowane klawisze modyfikujące)

derobert
źródło
1
Dziękujemy, w tym nazwa funkcji jest przydatna, gdy ludzie tacy jak ja natkną się na te pytania. Powiązane linki dla nieco więcej lektury: SO Pytanie i instrukcja bash
admdalldd 10.10.16
4

W Emacsie zwykle używałbym C-qdo oddzielenia argumentu przedrostka od wprowadzania cyfr.

Bash używa Ctrl+vzamiast C-q, aby uniknąć problemów z kontrolą przepływu XON / XOFF.

Więc możesz użyć Alt+1 Alt+6 Ctrl+v 0.

Toby Speight
źródło
3

inną opcją jest wpisanie czterech zer, a następnie użycie myszy do skopiowania i wklejenia go jeszcze trzy razy. kliknij dwukrotnie, aby wybrać, kliknij środkowym przyciskiem x 3, aby wkleić.

cas
źródło
Możesz też zagrać w golfa / oszukiwać, wpisując jeden zero, wybierz i wklej, aby uzyskać 2; wybierz i wklej, aby uzyskać 4; wybierz i wklej do 8, a następnie ponownie do 16. To jest wspaniałe :)
Jeff Schaller
tak, ale wpisanie 4 zer i wielokrotne wklejanie ich wydaje mi się optymalnym poziomem wysiłku w porównaniu do wypłaty. całe to dodatkowe kopiowanie i wklejanie wydaje się pracą.
cas
3

Gra z makrami:

Powiąż klawisz funkcyjny, F8aby pomnożyć przez dwa ostatnie słowo (w górę poprzedniej spacji) (kod klawisza F8 można znaleźć za pomocą Ctrl-V F8):

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

Można to zrobić na stałe, wysyłając ten sam tekst na adres ~/.inputrc

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

następnie wpisz:

echo 0F8F8F8F8

aby otrzymać 2 ^ 4 razy zero. (wciąż 5 naciśnięć klawiszy).

lub wpisz:

echo bookF8F8F8

uzyskać 2 ^ 3 słów książki.

Jeszcze szybciej:

Pomnóż przez 4:

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

echo 0F8F8

3 naciśnięcie klawisza.

Pomnóż przez 8 (ten sam numer co klawisz funkcyjny)

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

echo 00F8

Nadal 3 naciśnięcia klawiszy.

Oszukać?

Oszukiwać przez pomnożenie przez 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

Tylko 2 naciśnięcia klawisza. (i wciąż przydatna prosta funkcja)

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

Zwykłe oszukiwanie:

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

Echo F8

Tylko 1 (tak: jeden ) naciśnięcie klawisza.



Zmiana powiązania dla ctrl+U:

Wyślij to do ~/.inputrc:

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

Ponownie przeczytaj ~/.inputrcplik:

ctrl+Xctrl+R

rób to jak zwykle w emacsie (tak jak chciałeś):

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

7 klawiszy (po „ustawieniu”).

Nieco krótszy:

Użyj domyślnego „pomnóż przez 4” z „uniwersalnego argumentu” i zakończ z

 ctrl+V 0 

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

Tylko 5 kluczy.

Korzystanie z alt+ndostępu do (arg: n)

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

To 6 kluczy, aby uzyskać 16 zer.

Nie zmienia żadnego skrótu klawiaturowego:

Jeśli masz w swoim bashu bash C-u kills the currently-being-typed line.
To dlatego, że "\C-u":jest związany z unix-line-discard.

Ale to może również pomóc:
kiedy to, co jest przed usunięciem kursora, jest również umieszczane w „pierścieniu zabijania”.

Więc ctrl+uusuwa i ctrl+yodsuwa to, co zostało usunięte.
Na czystej linii: wpisz, 00skasuj i dwukrotnie pociągnij do tyłu, aby to zrobić 0000.
Powtórz, aby uzyskać 00000000(8 zer), w końcu wpisz polecenie i pociągnij dwa razy z powrotem.

Pierwszy zestaw (7 klawiszy pozostaje ctrlwciśnięty):

00 ctrl+Uctrl+Yctrl+Y ctrl+U 

Drugi zestaw (5 klawiszy)

ctrl+Uctrl+Yctrl+Y ctrl+U 

Otrzymasz osiem zer w pierścieniu kasowania, a następnie wpisz, co chcesz:

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

uzyskać:

foo --bar=baz 0000000000000000

Gdy wpadniesz na pomysł, możesz również wpisać to, czego potrzebujesz, przejść do początku linii ( ctrl-Y), zrobić jak wyżej (do ośmiu zer), przejść do końca ( ctrl-E) i szarpnąć dwa razy.

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

To 15 klawiszy (oprócz samego polecenia).
Nie krótko, wiem, ale to działa tylko z tym, co było dostępne.

To jest trochę krótsze:

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

To 11 kluczy

sorontar
źródło
Zobacz edycję mojej odpowiedzi ;-)
Stéphane Chazelas,
@ StéphaneChazelas Używasz makr? Baza 36? Tylko w Zsh? No dalej ... zobacz moją edycję :-P
sorontar 11.10.16
Cóż, tak, baza36 była trochę języczkiem w policzek. Podoba mi się, że F<n>powtarzasz ostatnie słowo <n>.
Stéphane Chazelas,
Zauważ, że nie wszystkie terminale wysyłają tę samą sekwencję na F8 (choć większość z tych znalezionych w systemach GNU / Linux wysyła ^[[19~). Zobacz, "$(tput kf8)"aby uzyskać informacje z bazy danych terminfo (lub $terminfohash in zsh).
Stéphane Chazelas,
@ StéphaneChazelas Tak, zgadza się. Lub po prostu użyjctrl-v F8
sorontar
2

Jako odmianę odpowiedzi cas wpisz

printf '0% .s' {1..16}Enter
a następnie użyj myszy, aby skopiować i wkleić (raz). Prawdopodobnie jest to O (log n), ale ponieważ jest to (len (str (n)) + 20), możesz uznać to za nieefektywne. Ale uwaga:

  • Byłem w stanie zgolić jedną postać - w moim systemie %.swydaje się zachowywać tak samo jak %.0s.
  • Jeśli chcesz uruchomić wiele poleceń 0000000000000000jako argument, musisz to zrobić tylko raz.

Glenn punkty Jackman odchodzący że (jeśli liczba jest dodatnia) drukuje ciąg ilość zer (i nowej linii), jak gwiazdka w formacie mówi do podjęcia szerokość pola z argumentów. W szczególności wydrukuje 16 zer. Ale jest to szczególny przypadek, który obsługuje tylko .  wydrukuje i wydrukuje komunikat błędu. Natomiast inne polecenia w tej odpowiedzi będą generować ciągi takie jak lub (i patrz poniżej ).printf "%0*d\n" number 0printfprintf "%0*d" 16 0 0printf "%0*d" 16 123450000000000012345printf "%0*d" 16 foo0000000000000000123451234512345…foofoofoo…7%7%7%...

Jeśli zamierzasz to robić często, możesz to usprawnić poprzez zdefiniowanie funkcji powłoki:

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

Uwagi:

  • Użyj $(seq 1 "$2")zamiast, (1.."$2"}ponieważ to drugie nie będzie działać - zobacz to , to , to i to . Pamiętaj, że niektóre odpowiedzi na te pytania sugerują użycie eval, ale generalnie nie jest to zalecane.
  • Łańcuch formatu ( $1%.0s) musi być w cudzysłowach (a nie w pojedynczych cudzysłowach), ponieważ zawiera parametr ( $1).
  • Ma --chronić przed $1wartościami zaczynającymi się od -.
  • Możesz uzyskać podobną ochronę, używając "%.0s$1"zamiast "$1%.0s".
  • Tak czy inaczej, $1wartość zawierająca %spowoduje zadławienie.
  • Jeśli potrzebujesz umieć obsługiwać $1wartości zawierające %, zrób

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

Po zdefiniowaniu takiej funkcji możesz także wykonywać takie czynności

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

który jest nieco mniej pisania niż "$(printf '0%.0s' {1..16})".

G-Man mówi „Przywróć Monikę”
źródło
Alternatywnie printf "%0*d" 16 0wydrukuje 16 zer. Gwiazdka w formacie pobierze szerokość pola z argumentów
glenn jackman