Inside the Unix system, you will find many small, hyper-specialized commands that does one thing (and does it well). You can chain these commands to work together to solve a complex problem. Wouldn't it be great if you can use these commands from inside Vim?
`:r` is Vim's read command. If you use it without `!`, you can use it to get the content of a file. If you have a file `file1.txt` in the current directory and you run:
```
:r file1.txt
```
Vim will put the content of `file1.txt` into the current buffer.
If you run the `:r` command followed by a `!` and an external command, the output of that command will be inserted into the current buffer. To get the result of the `ls` command, run:
The command `:w`, in addition to saving a file, can be used to pass the text in the current buffer as the STDIN for an external command. The syntax is:
When using the `:w` command, Vim uses all texts in the current buffer, similar to the global command (most command-line commands, if you don't pass it a range, only executes the command against the current line). If you pass `:w` a specific address:
```
:2w !node
```
Vim only uses the text from the second line into the `node` interpreter.
There is a subtle but significant difference between `:w !node` and `:w! node`. With `:w !node`, you are "writing" the text in the current buffer into the external command `node`. With `:w! node`, you are force-saving a file and naming the file "node".
It is imperative to pass a range to run the external command as a filter. If you try running the command above without the `.` (`:!tr '[:lower:]' '[:upper:]'`), you will see an error.
Let's assume that you need to remove the second column on both lines with the `awk` command:
```
:%!awk "{print $1}"
```
The result:
```
hello
hello
```
The breakdown:
-`:%!` executes the filter command on all lines (`%`).
You can chain multiple commands with the chain operator (`|`) just like in the terminal. Let's say you have a file with these delicious breakfast items:
```
name price
chocolate pancake 10
buttermilk pancake 9
blueberry pancake 12
```
If you need to sort them based on the price and display only the menu with an even spacing, you can run:
```
:%!awk 'NR > 1' | sort -nk 3 | column -t
```
The result:
```
buttermilk pancake 9
chocolate pancake 10
blueberry pancake 12
```
The breakdown:
-`:%!` applies the filter to all lines (`%`).
-`awk 'NR > 1'` displays the texts only from row number two onwards.
-`|` chains the next command.
-`sort -nk 3` sorts numerically (`n`) using the values from column 3 (`k 3`).
-`column -t` organizes the text with even spacing.
-`!j` runs the normal command filter operator (`!`) targetting the current line and the line below it. Recall that because it is a normal mode operator, the grammar rule `verb + noun` applies. `!` is the verb and `j` is the noun.
-`tr '[a-z]' '[A-Z]'` replaces the lowercase letters with the uppercase letters.
The filter normal command only works on motions / text objects that are at least one line or longer. If you had tried running `!iwtr '[a-z]' '[A-Z]'` (execute `tr` on inner word), you will find that it applies the `tr` command on the entire line, not the word your cursor is on.
Vim is not an IDE. It is a lightweight modal editor that is highly extensible by design. Because of this extensibility, you have an easy access to any external command in your system. Armed with these external commands, Vim is one step closer from becoming an IDE. Someone said that the Unix system is the first IDE ever.
The bang command is as useful as how many external commands you know. Don't worry if your external command knowledge is limited. I still have a lot to learn too. Take this as a motivation for continuous learning. Whenever you need to modify a text, look if there is an external command that can solve your problem. Don't worry about mastering everything, just learn the ones you need to complete the current task.