Bagaimana cara saya input dan pengulangan digit dalam bash, secara interaktif

20

Saya ingin menjalankan perintah

foo --bar=baz <16 zeroes>

Bagaimana cara saya mengetik 16 nol secara efisien *? Jika saya memegang Altdan menekannya 1 6 0akan mengulangi hal berikutnya 160 kali, yang bukan yang saya inginkan. Dalam emacs saya bisa menggunakan Alt-[number]atau Ctrl-u 1 6 Ctrl-u 0, tetapi dalam bash Ctrl-umembunuh baris yang sedang diketik dan nol berikutnya hanya menambahkan 0 ke baris.

Jika aku melakukan

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

Kemudian historymenunjukkan persis di atas, dan tidak foo --bar=baz 0000000000000000; yaitu bash tidak berperilaku seperti yang saya inginkan. ( Sunting : maksudnya, saya ingin memasukkan beberapa angka nol tanpa menggunakan $(...)substitusi perintah)

(*) Saya kira definisi teknis "efisien" adalah "dengan O (log n) penekanan tombol", lebih disukai sejumlah penekanan tombol yang sama dengan jumlah digit dalam 16 (untuk semua nilai 16) ditambah mungkin konstanta; contoh emacs memenuhi syarat sebagai efisien dengan definisi ini.

Jonas Kölker
sumber
1
Sepertinya Anda ingin bash entah bagaimana caranya know what you want to do. Dalam perintah bertingkat yang kompleks, bagaimana bash akan tahu bagian mana yang ingin Anda lihat hasil eksekusi dalam sejarah sebagai lawan dari perintah itu sendiri? Bagaimana dengan variabel? Singkatnya bash selalu akan memiliki codedalam sejarah, bukan hasil dari mengeksekusi kode.
Orang tidak percaya
@meuh, Altdengan sendirinya tidak mengirim karakter apa pun, jadi menekan dan melepaskan alt tidak akan memiliki efek sejauh bashyang bersangkutan.
Stéphane Chazelas
1
@Unbeliever Lakukan Apa yang kumaksud dan itu akan baik-baik saja
kucing
@ Unnbeliever: lihat edit saya — inti paragraf yang berhubungan dengan historyadalah bahwa saya ingin memasukkan angka tanpa menggunakan substitusi perintah.
Jonas Kölker
Kapan pun Anda ingin segala sesuatu diketik secara otomatis untuk Anda, AutoKey adalah utilitas yang bagus untuk digunakan. Dengan itu, Anda bisa membuat pergantian frase, atau menyelesaikan makro Python yang akan melakukan apa saja yang Anda suka ketika frasa pemicu diketik atau tombol pintas ditekan. Saya tidak memasukkan ini sebagai jawaban karena memerlukan lingkungan desktop GUI dan sisanya tidak - dan karenanya lebih umum berlaku.
Joe

Jawaban:

25

Mencoba

gema Alt+1Alt+6Ctrl+V0

Itu 6 stroke kunci (dengan asumsi keyboard QWERTY AS / Inggris setidaknya) untuk memasukkan 16 angka nol (Anda bisa tahan Altuntuk 1 dan 6).

Anda juga bisa menggunakan vimode standar ( set -o vi) dan mengetik:

gema 0 Escx16p

(juga 6 stroke kunci).

The emacsmodus setara dan yang dapat digunakan untuk mengulang lebih dari satu karakter ( ) bekerja dalam , tetapi tidak dalam .echo 0Ctrl+WAlt+1Alt+6Ctrl+Yzshbash

Semua itu juga akan bekerja dengan zsh(dan dari tcshmana asalnya). Dengan zsh, Anda juga bisa menggunakan flag ekspansi variabel padding dan memperluasnya dengan Tab:

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

(Lebih banyak penekanan tombol jelas).

Dengan bash, Anda juga dapat bashmemperluas $(printf '0%.0s' {1..16})dengan Ctrl+Alt+E. Perhatikan bahwa itu akan memperluas segala sesuatu (bukan gumpalan) di telepon.

Untuk memainkan gim dengan pukulan tombol paling sedikit, Anda dapat mengikat beberapa tombol dengan widget yang meluas <some-number>Xhingga Xberkali- <some-number>kali. Dan ada <some-number>di base 36 untuk lebih mengurangi itu.

Dengan zsh(terikat pada 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

Lalu, untuk 16 nol, Anda mengetik:

gema g0F8

(3 keystrokes) di mana gadalah 16dalam basis 36.

Sekarang kita bisa menguranginya menjadi satu kunci yang menyisipkan 16 angka nol itu, meskipun itu akan curang. Kita dapat mengikat F2dua 0s (atau dua $STRING, 0 secara default), F3menjadi 3 0s, F1F6hingga 160 s ... hingga 19 ... kemungkinan tidak ada habisnya ketika Anda dapat menentukan widget acak.

Mungkin saya harus menyebutkan bahwa jika Anda menekan dan menahan 0tombol, Anda dapat memasukkan angka nol sebanyak yang Anda inginkan hanya dengan satu penekanan tombol :-)

Stéphane Chazelas
sumber
Terima kasih telah memberikan banyak variasi untuk vidan lainnya!
Mark Stewart
9

Menganggap emulator terminal Anda tidak memakan keystroke (misalnya, untuk berganti tab) - dataran xterm berfungsi - Anda dapat menekan Alt-1 6 Ctrl-V 0. Kontrol-V diperlukan di sana untuk memecah nomor dan karakter untuk mengulangi (jika Anda mengulangi surat, Anda tidak akan membutuhkannya).

(Ini adalah fitur readline yang dikenal sebagai digit-argument, jadi Anda harus dapat menggunakan binduntuk mengubah kunci pengubah yang terlibat)

derobert
sumber
1
Terima kasih, termasuk nama fitur ini berguna ketika orang-orang seperti saya tersandung pada pertanyaan-pertanyaan ini. Tautan terkait untuk membaca lebih lanjut: SO Pertanyaan dan manual bash
admalledd
4

Di Emacs, saya biasanya menggunakan C-quntuk memisahkan argumen awalan dari input digit.

Bash menggunakan Ctrl+valih-alih C-q, untuk menghindari masalah dengan kontrol aliran XON / XOFF.

Jadi bisa digunakan Alt+1 Alt+6 Ctrl+v 0.

Toby Speight
sumber
3

Pilihan lain adalah mengetik empat nol dan kemudian menggunakan mouse untuk menyalin dan menempelkannya tiga kali lagi. klik dua kali untuk memilih, klik tengah x 3 untuk menempel.

cas
sumber
Atau golf / curang lagi dengan mengetik satu nol, pilih & rekatkan untuk mendapatkan 2; pilih & rekatkan untuk mendapatkan 4; pilih & rekatkan ke 8, dan lagi untuk 16. Ini POWerful :)
Jeff Schaller
ya, tapi mengetik 4 nol dan mengulangi menyisipkan tampaknya tingkat upaya yang optimal vs imbalan kepada saya. semua itu menyalin dan menempel ekstra sepertinya bekerja.
cas
3

Bermain dengan makro:

Ikat tombol fungsi F8untuk mengalikan dua kata terakhir (naik spasi sebelumnya) (kode kunci F8 ditemukan dengan menggunakan Ctrl-V F8):

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

Itu bisa dibuat permanen dengan mengirim teks yang sama ke ~/.inputrc

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

lalu ketik:

gema 0F8F8F8F8

untuk mendapatkan 2 ^ 4 kali nol. (masih 5 penekanan tombol).

atau ketik:

buku gemaF8F8F8

untuk mendapatkan 2 ^ 3 kata buku.

Masih lebih cepat:

Kalikan dengan 4:

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

gema 0F8F8

3 penekanan tombol.

Kalikan dengan 8 (angka yang sama dengan tombol fungsi)

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

gema 00F8

Masih 3 penekanan tombol.

Curang?

Cheat dengan mengalikan 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"'

gema 0F8

Hanya 2 penekanan tombol. (dan masih fungsi sederhana yang bermanfaat)

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

Kecurangan polos:

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

gema F8

Hanya 1 (ya: satu ) keystroke.



Mengubah pengikatan untuk ctrl+U:

Kirim ini ke ~/.inputrc:

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

Baca ulang ~/.inputrcfile:

ctrl+Xctrl+R

lakukan seperti biasa di emacs (seperti yang kamu inginkan):

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

7 tombol (setelah "pengaturan").

Sedikit lebih pendek:

Gunakan "kalikan dengan 4" dari "argumen universal" dan akhiri dengan

 ctrl+V 0 

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

Hanya 5 kunci.

Menggunakan alt+nakses ke (arg: n)

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

Itu 6 kunci untuk mendapatkan 16 angka nol.

Tidak mengubah pintasan keyboard apa pun:

Jika di bash Anda, Anda miliki bash C-u kills the currently-being-typed line.
Itu karena "\C-u":terikat unix-line-discard.

Tapi itu mungkin juga membantu:
Kapan, apa yang sebelum kursor dihapus, itu juga ditempatkan di "cincin bunuh".

Jadi ctrl+umenghapus dan ctrl+ymenarik kembali apa yang terhapus.
Pada garis yang bersih: Ketik 00hapus dan tarik kembali dua kali untuk membuatnya 0000.
Ulangi untuk mendapatkan 00000000(8 nol), akhirnya ketik perintah dan tarik kembali dua kali.

Set pertama (7 tombol terus ctrlditekan):

00 ctrl+Uctrl+Yctrl+Y ctrl+U 

Set kedua (5 tombol)

ctrl+Uctrl+Yctrl+Y ctrl+U 

Itu akan mendapatkan delapan nol di cincin hapus, lalu ketik apa yang Anda inginkan:

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

mendapatkan:

foo --bar=baz 0000000000000000

Setelah Anda mendapatkan ide, Anda juga bisa, ketik apa yang Anda butuhkan, pergi ke awal baris ( ctrl-Y), lakukan seperti di atas (hingga delapan nol) pergi ke akhir ( ctrl-E) dan mencabut dua kali.

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

Itu 15 kunci (di samping perintah itu sendiri).
Tidak pendek, saya tahu, tetapi itu hanya bekerja dengan apa yang tersedia.

Ini sedikit lebih pendek:

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

Itu 11 kunci

sorontar
sumber
Lihat hasil edit jawaban saya ;-)
Stéphane Chazelas
@ StéphaneChazelas Menggunakan makro? Basis 36? Hanya di zsh? Ayo ... lihat edit saya :-P
sorontar
Ya, base36 itu agak menjilat. Saya suka Anda F<n>menduplikasi waktu kata terakhir <n>.
Stéphane Chazelas
Perhatikan bahwa tidak semua terminal mengirim urutan yang sama pada F8 (meskipun sebagian besar yang ditemukan pada sistem GNU / Linux mengirim ^[[19~). Lihat "$(tput kf8)"untuk mendapatkan informasi dari basis data terminfo (atau $terminfohash dalam zsh).
Stéphane Chazelas
@ StéphaneChazelas Ya, itu benar. Atau cukup gunakanctrl-v F8
sorontar
2

Sebagai variasi dari jawaban cas , ketikkan

printf '0% .s' {1..16}Enter
dan kemudian gunakan mouse untuk menyalin dan menempelnya (satu kali). Bisa dibilang, ini O (log n), tetapi karena itu (len (str (n)) + 20), Anda mungkin menganggapnya tidak efisien. Tapi perhatikan:

  • Saya dapat mencukur satu karakter - pada sistem saya, %.stampaknya berperilaku sama seperti %.0s.
  • Jika Anda ingin menjalankan beberapa perintah dengan 0000000000000000sebagai argumen, Anda hanya perlu melakukan ini sekali.

glenn jackman menunjukkan bahwa (di mana angka adalah bilangan bulat positif) akan mencetak string angka nol (dan baris baru), sebagaimana tanda bintang dalam format memberi tahu untuk mengambil lebar bidang dari argumen. Secara khusus, akan mencetak 16 nol. Tetapi ini adalah kasus khusus yang hanya menangani .  akan mencetak , dan akan mencetak dan pesan kesalahan. Sebaliknya, perintah lain dalam jawaban ini akan menghasilkan string seperti atau (dan lihat di bawah untuk ).printf "%0*d\n" number 0printfprintf "%0*d" 16 0 0printf "%0*d" 16 123450000000000012345printf "%0*d" 16 foo0000000000000000123451234512345…foofoofoo…7%7%7%...

Jika Anda akan melakukan ini secara rutin, Anda dapat merampingkannya dengan mendefinisikan fungsi shell:

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

Catatan:

  • Gunakan $(seq 1 "$2")alih-alih (1.."$2"}karena yang terakhir tidak akan berfungsi - lihat ini , ini , ini , dan ini . Perhatikan bahwa beberapa jawaban untuk pertanyaan itu menyarankan untuk digunakan eval, tetapi ini umumnya tidak disarankan.
  • String format ( $1%.0s) harus dalam tanda kutip ganda (bukan tanda kutip tunggal) karena mengandung parameter ( $1).
  • The --adalah untuk melindungi $1nilai-nilai dimulai dengan -.
  • Anda bisa mendapatkan perlindungan serupa dengan menggunakan "%.0s$1"bukan "$1%.0s".
  • Either way, $1nilai yang mengandung %akan membuatnya tersedak.
  • Jika Anda harus dapat menangani $1nilai yang mengandung %, lakukan

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

Juga, setelah Anda memiliki fungsi yang didefinisikan, Anda dapat melakukan hal-hal seperti

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

yang sedikit mengetik kurang dari "$(printf '0%.0s' {1..16})".

G-Man Mengatakan 'Reinstate Monica'
sumber
Bergantian printf "%0*d" 16 0akan mencetak 16 nol. Tanda bintang dalam format akan mengambil lebar bidang dari argumen
glenn jackman