Command Line Tips (part I: simple key bindings) 1
Working on the command line can seem daunting and slow. With a few handy tips working on the command line can be productive and efficient.
This entry is the first of a few to cover some of the command line techniques I use to be more productive on the command line.
Before we get started, there are two things I should cover.
- It’s all bash/ sh. Other shells are great, but I don’t know them. Bash is pretty much the default in Linux distros these days, which is probably why I wound up learning it.
- This is geared toward the beginner, and is aimed at interactive use as opposed to programming.
- [ctrl] commands are a simultaenous press. Press both keys at the same time.
- [esq] commands require that you press escape, then let off, then press the next key.
The most general key bindings used in bash are for history navigation and command editing. The ones I commonly use are:
| [arrow up] or [ctrl]-p | Move back in command history |
| [arrow down] or [ctrl]-n | Move forward in command history |
| [ctrl]-a | move cursor to begining of line |
| [ctrl]-e | move cursor to end of line |
| [ctrl]-k | erase to end of line |
| [esq]-b | skip back one word |
| [esq]-f | skip forward one word |
| [esq]-d | erase word to right of cursor |
| [ctrl]-r | backward history search* |
The [ctrl]-r requires some explanation.
When you hit [ctrl]-r, you are in a history search mode, typing further characters performs an auto-complete style search of your command history.
By typing ‘if’ at this prompt, I find that I have a match ’/sbin/ifconfig -a’, which I’d recently executed.
(reverse-i-search)`': (reverse-i-search)`if': /sbin/ifconfig -a
Pressing enter then executes the command. Other keys like cursor navigation will bring you back to regular command prompt mode, and allow you to edit the command.
Good luck and have fun!
Pipes and commands 2
I received a question from a co-worker the other day about why “ls | grep [something]”
returns single file names. When ls is run by itself in a terminal window, it shows output in columns (multiple files per line). The grep command works at the line level, not the field level. Why does ls | grep not return a line with multiple file names?
Commands like ls can detect if the input or output streams (standard input and standard output) are pipes. Armed with this information they alter their output to be more sensible for the context in which they are run.
The following example C program demonstrates:
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int main() {
struct stat *st = malloc(sizeof stat);
if(fstat(1, st) != 0) {
fprintf(stderr, "Could not stat standard output...\n");
exit(1);
}
if(S_ISFIFO(st->st_mode)) {
printf("Standard output is a pipe.\n");
} else {
printf("Standard outpt is not a pipe.\n");
}
}
I then compiled and ran the program both with and without a pipe:
alibby@alibby-laptop:~$ gcc -o pipedetect pipedetect.c alibby@alibby-laptop:~$ ./pipedetect Standard outpt is not a pipe. alibby@alibby-laptop:~$ ./pipedetect | cat Standard output is a pipe. alibby@alibby-laptop:~$
So ls and other commands are nice enough to detect when a pipe is being used on
standard out and present one line. In this case the ls command presents one file
per line (which is what we want when grepping).
GNU ls is nice enough to provide the --format=single option to provide this behavior
when a pipe is not used.
For more information about what’s going on in the C app above, you can consult
manual pages for stat(2).
