Shellkonfiguration – Übersicht
Über viele Jahre war eine meiner Standardmaßnahmen zur Erhöhung meiner Produktivität und Erleichterung meines Linux-Lebens, immer einen Editor mit einen oder mehreren Textdateien geöffnet zu haben, in denen ich nützliche, schwer zu merkende oder nur selten benötigte Linux-Kommandos archiviert habe. So nützlich und trivial umsetzbar dies ist, diese Vorgehensweise hat Nachteile:
Diese Sammlung wird schnell unübersichtlich, und der Hauptzweck daneben, die Information überhaupt verlässlich zu finden, ist, sie schnell zu finden.
Dieser Ansatz verleitet dazu, nur wenig Informationen pro Thema zu erfassen, weil es anderenfalls noch unübersichtlicher wird.
Man muss – wenn man (wie ich) zumeist in der Shell unterwegs ist – zwischen der Shell und dem Editor wechseln (und dort den einzelnen Dateien), was den ganzen Vorgang nicht gerade beschleunigt.
Die gesammelten Informationen sind im allgemeinen wenig hilfreich für andere, auch wenn sie die Vorgehensweise übernehmen mögen.
Eine wesentlich bessere Vorgehensweise ist, für jedes Thema (mindestens) eine eigene Textdatei zu haben und diese über eine Shell schnell zugänglich zu machen. Textdateien kann jeder trivial selber erstellen oder anpassen. Man kann für seine Organisation einige Dateien zentral bereitstellen, die für mehrere Leute nützlich sind. Diese können die User dann in ihrem Homeverzeichnis durch andere Dateien ergänzen oder die bestehenden für ihre eigene Nutzung überschreiben.
Mein Ansatz ist, ein gemeinsames Präfix (z.B oh-
für Onlinehilfe) für alle diese Shellfunktionen zu definieren, so dass man sich in der Shell mit tab completion (o h - Tab) alle verfügbaren Hilfetexte anzeigen lassen kann. Wenn man sehr viele Texte dieser Art hat, mag man die Textdateien in Verzeichnissen thematisch sortieren (was der folgende Code noch nicht vorsieht). Man kann auch mehrere Dateien zum selben Thema anlegen, etwa vim.txt für grundlegende Informationen und vim-adv.txt für fortgeschrittene Anwender.
Der Name der Textdateien (vor der Endung) muss ein gültiger Shellfunktionsname sein.
Diese Funktion kann man in .bashrc einlesen lassen.
init_online_help () { local -r OHFILES_PERSONAL_DIR_PATH=~/'online-help' OHFILES_SYSTEM_DIR_PATH='/usr/share/online-help' local -r FILE_SUFFIX='.txt' FUNCTION_PREFIX='oh-' FILEBASENAME_REGEX='^[a-zA-Z0-9_-]+$' local shopt_state file_path function_name file_basename local -a existing_functions shopt_state="$( shopt -p )" shopt -s nullglob globasciiranges existing_functions=( $( compgen -A function "$FUNCTION_PREFIX" ) ) for function_name in "${existing_functions[@]}"; do unset -f "$function_name" done for file_path in "${OHFILES_SYSTEM_DIR_PATH}/"*"${FILE_SUFFIX}" "${OHFILES_PERSONAL_DIR_PATH}/"*"${FILE_SUFFIX}"; do file_basename="${file_path##*/}" file_basename="${file_basename%"${FILE_SUFFIX}"}" : "$file_basename" "$FILEBASENAME_REGEX" if [[ $file_basename =~ $FILEBASENAME_REGEX ]]; then function_name="${FUNCTION_PREFIX}${file_basename}" eval function "${function_name}" "() { online-help-output ${file_path@Q}; }" else echo "ERROR: The file basename '${file_basename}' does not match the regex '${FILEBASENAME_REGEX}'; skipping" fi done eval "$shopt_state" } # init_online_help () init_online_help unset -f init_online_help online-help-output () { LESS= command less --prompt='[less] Press q to exit, h for help' -WiJNSq --incsearch --line-num-width=3 "$1" } # online-help-output ()
Wofür man Hilfetexte benötigt und wie die gestaltet sein sollten, ist natürlich hochgradig subjektiv. Diejenigen, die ich bisher für mich erstellt habe, haben wenig mit meinen früheren Editor-Notizen gemeinsam – weil ich sie mit dem Hintergedanken erstellt habe, dass sie auch von Kollegen genutzt werden.
less commands are similar to vim commands q or Q or :q or :Q or ZZ : Exits less less [+cmd] [--] [filename]... : e.g. less +/nobody /etc/passwd : man bash | command less +/'^ Arrays' # less must read the whole input in order to show the percentage in the status line at the bottom. Use --file-size or press Gg less +G +g /etc/passwd ### movement # go to the top / end / line 25 / 25% of the file g / G / 25g / 25p # go to the next / previous file in the command line list :n / :p # go to mark a 'a ### /pattern search # forward / backward search for regex /regex / ?regex # go to the next / previous / third match in / against search direction (/regex<Enter>n and ?regex<Enter>N both go forward in the buffer) n / N / 3n / 3N # At the beginning of the pattern these characters modify the type of search rather than become part of the pattern: ^N or ! : Search for lines which do NOT match the pattern ^E or * : Search multiple files. That is, if the search reaches the END of the current file without finding a match, the search continues in the next file in the command line list. ^K : Highlight any text which matches the pattern on the current screen, but don't move to the first match (KEEP current position). ^R : Don't interpret regular expression metacharacters; that is, do a simple textual comparison. ^W : WRAP around. If the search reaches the end of the current file without finding a match, the search continues from the first line of the current file up to the line where it started. ### display ESC-u Undo (toggle) search highlighting. &pattern * Display only matching lines.
terse help: H beginning / end of page: b/e scroll forward / backward: <space>/<del> search forward: s previous occurrence { next occurrence } search index i incremantal search ^S/^R next menu entry <Tab> menu m [<Tab>]
default escape (leader) key: ^A (client console), ^Q (Linux VM), ^B (tmux default) main menu: <leader>-* session menu: <leader>-^S pane menu: <leader>-^P detach tmux (background): <leader>-d create new window: <leader>-c go to window with index 2: <leader>-2 go to next window: <leader>-n go to previous window: <leader>-p
### vim modes # switch to: normal mode (from all other modes) / (from normal mode:) insert mode / command mode / visual mode <Esc> / i / a / c / s / o / : / v ### main commands (except motion commands) in normal mode # copy (yank) / paste (put) / delete / change (delete and continue in insert mode) / substitute (delete number of characters + insert mode) / create empty line below y[motion command] / p / d[motion command] / c[motion command] / [number of characters, default 1]s / o # replace the character under the cursor with x / replace the following characters until <Esc> is pressed rx / R ### search / filter # search downwards / upwards /regex / ?regex # jump to next match in / in opposite direction n / N # jump to next / previous occurrence of the word under the cursor (matching whole words only) // matching the string anywhere * / # / g* / g# # list all lines found in current and included files that contain the word under the cursor [I ### vim help # go to entry p (normal mode) / sp (command mode) / ^R (insert mode) / o (visual mode) / functions :h p / :h :sp / :h i_CTRL-R / :h v_o / :h substitute() # search for word 'motion' in help / open / close quickfix list with all matches :helpgrep motion / :copen / :cclose ### show information # in normal mode <Ctrl>-g shows in the status line: # The buffer ID, the full path, the number of lines, and the line percentile ### motion commands # go to start / end of file / line 5 / column 5 / the 5% line (percentage of lines not file size) gg / G / (( 5G / :5 )) / 5| / 5% # go to beginning / first non-blank character / 25% / middle / last non-blank character / end of line 0 / ^ / 25gM / gM / g_ / $ # go 5 line up / down 5- / 5+ # go to the beginning of word (word characters) / WORD (non-whitespace) to the right w / W # go to the end of word (word characters) / WORD (non-whitespace) to the right // word / WORD to the left e / E / ge / gE # go [count] sentences / paragraphs backward // sentences / paragraphs forward ( / { / ) / } # go to the beginning of word (word characters) / WORD (non-whitespace) to the left b / B # go to (the character before) / the first character x to the right / left; go to the next match in the same / opposite direction tx / fx / Tx / Fx / ; / , ### operations on several lines # delete / change (delete and edit) / copy / mark (visual mode) 5 lines (current line plus four) 5dd / 5cc / 5yy / V4j ### (character-wise) area definitions # <command> a/i <area>: a (including borders) / i (between borders) # " / ' / ( / { / [ / < / s (sentence) / p (paragraph) / t (<p>tags</p>) # possible commands: v / y / d / c ### show register content (from copy or delete) :reg ### windows (views) / buffers (files) # open vim with several windows top-bottom / left-right vim -o / -O file1 file2 ... # split window top-bottom / left-right :sp / :vsp # move cursor to another window: [count] window(s) to the left / bottom / above / right // bottom / top window ^Wh / ^W<arrow key> / ^Wj / ^W<arrow key> / ^Wk / ^W<arrow key> / ^Wl / ^W<arrow key> / ^Wb / ^Wt ### saving buffers / closing windows # save current buffer / all buffers without closing a window :w / :wa # close un- / modified window without / with saving :q / :q! / :wq # close all un- / modified windows without / with saving :qa / :qa! / :wqa
### show information # buffers :ls # registers (yank / delete content) :reg # print ASCII hex value / value of bytes used in UTF-8 character under the cursor ga / g8 ### editing ## replace / insert # replace the next five characters with x 5rx # insert 5x 5ix ## paste # paste character register as line below :pu / :put # paste before the current line (like "P"; no variante for pasting below...), but adjust indent to current line [p / [P # join lines with / without inserting space J / gJ ### block operations # mark block / move cursor to the opposite end of the marked block (for changing the start/end position) ^V <arrow>... / o # delete marked block d # insert same text before the marked block in all lines of the block ^V <arrow>... I <text> <esc> ### windows # go to previous (last accessed) window ^Wp ## change window size # height / width [number]^W+ / [number]^W- / [number]^W> / [number]^W< # equalize width and height of all windows <Ctrl>-w = # close all but current window (like :only) ^Wo ## move windows within the same tab # rotate all windows / move window one position to the left / below / to the right / above ^Wr / ^Wh / ^Wl / ^Wj / ^Wk # move window to the left / bottom / top / right border or the tab (and expanding it to the whole height / width of the tab) ^WH / ^WL / ^WJ / ^WK ### motion commands # go to [count] byte in the buffer go # go to first / last character of the previously changed or yanked text `[ / `] # go to the first / last character of the last selected Visual area `< / `> # go to the position where the cursor was the last time when Insert mode was stopped gi / `^ # go to the position where the last change was made / older changes `. / g; ## jumps / changes # show jump / change list :jumps / :changes # jump commands: "'", "`", "G", "/", "?", "n", "N", "%", "(", ")", "{", "}", :s # go to the position before the latest jump, or where the last "m'" or "m`" command was given `` # go to older / newer position in jump // change list ^O / ^I / g; / g, ### motion commands in wrapped lines # go to first / first non-blank character of the screen line / middle of the screen / last non-blank character / last character of the screen line g0 / g^ / gm / g<End> / g$ # go [count] screen lines down / up gj / gk ### work-around for missing zoom # maximize window height / width / open current window in another tab (can be closed afterwards) ^W_ / ^W| / :tab sp # does not restore old window sizes ^W= ### tab operations # create new tab and edit file / with an empty buffer / close tab :tabedit file / :tabnew / :tabclose # go one tab to the right / left / go to the tab with index 3 / go to the last active tab gt / gT / 3gt / g<Tab> # edit file name under the cursor in a new tab page (ignoring ":${line_number}" after the path) / and jump to the line number following the file name ^Wgf / ^WgF # move current window to a new tab page ^WT ### buffer operations # list open buffers / switch to buffer / destroy buffer :ls / :b ID / :bd ### different read-only levels # read-only, override with :w! vim -R file / :tab sview file # disable modification to any file, allow modifications to the buffer; global option 'write' vim -m file / :set write! # disable modifications to any buffer (command line option) / the current buffer (set); local option 'modifiable' / 'ma' vim -M file / :set modifiable! ### jumplist (special cursor position changes (excluding ecplicit motion commands), e.g. searches) # go to previous / next jump position / show jump / change list ^O / ^I / :jumps / :changes # jump to the line / exact position of last {change} / {exit from insert mode} '. / `. / '^ / `^ / gi # go to older / newer position in the change list g, / g; ### marks (a-z per file, A-Z global) # set mark a / show marks / go to the {beginning of the line} / {exact position} of mark a ma / :marks / 'a / `a # set beginning / end mark for visual region (gv) m< / m> # go to the {beginning of the line} / {exact position} of the next / previous (lowercase) mark ]' / ]` / (previous:) [' / [` # charset (set fileencoding?) :set fileencoding=utf8 ### convert spaces to tabs (tab := 8 spaces) :retab! 8 # overwrites the value of 'tabstop-Wert' so afterwards: :set tabstop=4 ### visual mode # increase / decrease indentation (default: 1 step) [number of steps]> / [number of steps]< # select the same area as before (until e.g.: v / y) gv # paste so that the pasted text can be selected with gv afterwards: # 1) (usually:) create a new line as the selected area will be overwritten: o<Esc> # 2) v # 3) P # 4) delete the line above # 5) gv ### folds # compact the selected lines to a fold zf # open / close the fold under the cursor za # enable / disable folding (open / close all closed folds simultaneously) za ### completing words / word order (insert the word(s) after the completion match) / line / file path in insert mode / abort completion ^X^N / ^X^N^X^N / ^X^L / ^X^F / ^E /etc/passwd ### use file path under cursor # open file in the same / in a new window / in a new tab gf / ^W^F / ^Wgf ### non-breakable space character # 0xA0 (160 decimal) and U+202F CTRL-V xa0 / u00a0 / u202f