Last updated on Mon Jul 26 12:57:00 CEST 2021.
This page is a collection of simple tips for working with and on UNIX that don't deserve a page of their own.
The following sh snippet modifies the members of $@ by processing them with COMMAND. It successfully retains the structure of $@ and handles whitespace correctly.
i=0 while [ $((++i)) -le $# ]; do a=`COMMAND $1` shift set -- "$@" "$a" done
The quickest way to move the cursor to a specific place in the document is to use the search commands, // and ??. Remember that // and ?? can be used as motions, too: d/x^M deletes everything until the next occurrence of "x".
However, you often want to delete everything before "x" as well as "x" itself. While vi offers no built-in command for this, the following mapping often works well enough [1]:
map ^M :s///^M
That maps the Return key to delete the first occurrence of the previously searched phrase on the current line. It works as long as "x" is sufficiently unique.
Fortunately, you're likely to notice if it deletes the wrong thing, as (at least my implementation of) vi will move you to the beginning of the line if it deletes anything before the cursor.
If you really want a command that reliably deletes the found phrase, and not the same phrase earlier in the same line, the following should do the trick:
map ^M i^M^[:s///^Mk:j^Ml
Note that it doesn't work if you move after your search. Another drawback is that it requires multiple undos to undo.
Well-formatted C code writes function definitions like this:
int main(...) { ... }
This makes it easy to find function definitions with regular expressions. The following command finds the definition of the parse function, searching all C source files in the current directory:
$ grep -n ^parse\( *.c util.c:342:parse(char *s)
For quick selection of common source files, I recommend adding a few variable definitions in .shrc:
a='* */*' c='*.[ch] */*.[ch]' p='*.p[lm] */*.p[lm]'
For example, the following invocation searches through all C source and header files in the current directory and all subdirectories:
grep -n ^Render $c
To make this pattern even more useful, I use a script called dwim [2] to translate the results (util.c:342) to the corresponding vi invocation:
$ dwim util.c:342 # runs "vi +342 util.c"
To write and format printed documents, I mainly use troff, but the idiosyncratic syntax sometimes makes troff source code difficult to navigate.
Fortunately, vi supports troff syntax by default:
There are two options called paragraphs and sections, which define the names of the matching macros:
set para=IPLPPPQPP\ LIpplpipbp set sect=NHSHH\ HUnhsh
Note that it only supports matches with one or two characters. Note also the (escaped) spaces for specifying one-character macros.
xterm is my personal favorite among terminal emulators, but it takes a substantial amount of time to start (ca 0.40s) if UTF-8 is enabled. The solution is to launch xterm with UTF-8 disabled, but enable it afterwards.
Compare:
$ time LC_ALL=en_US.UTF-8 xterm -e exit 0.38s real 0.17s user 0.04s system $ time LC_ALL=en_US.ISO8859-1 xterm -e exit 0.15s real 0.06s user 0.05s system
UTF-8 can be enabled by sending a special control sequence to xterm:
$ echo -n '^[%G' # set encoding to utf-8 $ echo -n '^[%@' # set encoding to iso8859-1
(^[ represents a literal escape character.)
The following C program does exactly that:
#include <err.h> #include <unistd.h> int main(int argc, char *argv[]) { /* Enable UTF-8 encoding in xterm. */ write(0, "\033%G", 3); if(argv[1]){ execvp(argv[1], argv+1); err(1, "execvp"); } }
I call it u. You can use it like this:
$ xterm -e u ksh # or whichever shell or program
Here's something I often want to do, but which Git makes a bit awkward: checkout the previous version of a file without overwriting the current one.
To solve this problem, I've written a script called git-orig:
#!/bin/sh # git-orig -- checkout original file [ $# -lt 2 ] && { echo "usage: $0 head file [...]" 1>&2; exit 1; } h=$1 shift set -e for f in "$@"; do mv -i "$f" "$f".new done git checkout "$h" -- "$@" git reset "$@" >/dev/null for f in "$@"; do mv -i "$f" "$f".orig mv "$f".new "$f" done
With this script in your PATH, the following command checks out v_sentence.c as of 3f2c76b486dc55336cabdc38ae5dd3ad317b16a4:
$ git orig 3f2c76b486dc55336cabdc38ae5dd3ad317b16a4 v_sentence.c
The checked out file is named v_sentence.c.orig.
One of the things I love about Plan 9 is that its default console doesn't automatically scroll to the bottom of command output. Unfortunately, almost no terminal emulators for UNIX support this behavior.
Or so I thought! It turns out that xterm has a resource named allowScrollLock, which is false by default. If you set it to true, you can press Scroll Lock to temporarily disable xterm's automatic scrolling.
This doesn't exactly mirror Plan 9's behavior, as Scroll Lock prevents the screen from scrolling on key press, but it's good enough for most cases.