There are many tools that I use to improve my terminal experience, these are the top five that I use every single day to make developing code easier, quicker, and more enjoyable.
ack
Starting with the most well known first, ack
is like grep
but optimized for programmers, it is both faster and simpler than grep
, and has better results.
ack
has several quality of life improvements by default: recursive by default (but ignores VCS folders like .git), better output display including highlighting, and it uses PCRE for pattern matching.
Just compare the default output for grep -R
and ack
(respectively):
Search for “Interface” in the “src” directory using grep: grep -R Interface src
The same search using ack: ack Interface src
Sure, the output for ack
takes up far more space, but it groups matches by filename (highlighted), adds line numbers, and highlights the matching text.
Additionally, you can easily include specific file types using the -t
or --type=
flags, e.g. to only search PHP file types which includes .php .phpt .php3 .php4 .php5 .phtml
and files with a PHP shebang (e.g. #!/usr/bin/env php
) on the first line you can use -t php
or --type=php
. You can also use the type name itself as a flag instead e.g. --php
.
You can easily expand these types by adding a .ackrc
file to your HOME directory and with a few lines either add additional file matches, or add a new file type entirely. For example, you can use --type-add
to add composer.json
(specifically) as a filename to search when searching through php
file:
--type-add=php:is:composer.json
You can create a new file type for .env
files called env
:
--type-set=env:ext:env
--type-add=env:match:/^.env.*$/
Or to create a new file type for blade templates:
--type-set=blade:match:/.blade.php$/
With these in place a search for ack --php dshafik/bag
will return results from composer.json
, while a search for ack --blade someVariables
will only match results in *.blade.php
files, and ack --env APP
will match all lines containing APP
in your .env*
files.
delta
delta
describes itself as “a syntax-highlighting pager for git, diff, grep, and blame output”, but I find that to be somewhat ambiguous: it is a syntax-highlighting pager for git diff
, git grep
, and git blame
output. It will actually be used by all git operations that output diffs, not just git diff
.
Integration with git
is easy, just add the following to the .gitconfig
file in your HOME directory:
[core]
pager = delta
[interactive]
diffFilter = delta --color-only
[delta]
navigate = true # use n and N to move between diff sections
# delta detects terminal colors automatically; set one of these to disable auto-detection
# dark = true
# light = true
[merge]
conflictstyle = diff3
[diff]
colorMoved = default
Personally, I also like to add line-numbers = true
to the [delta]
configuration to enable line numbers.
Once you’ve completed this, git
will start to output much easier to read diffs:
As you can see here, it calls out the filename at the top, and is smart enough to show the relevant code structure that contains the change and the line on which the diff context starts, in this case the namespace, starting from line 7, but it could also be a class or a function or method. It also features per-character diff highlighting, on top of the standard line highlighting — in this case you can see that I added a new value to the Attribute options bit mask.
httpie
The next tool has been in my toolkit for a long time, httpie, a python tool for making HTTP requests. It is usually referred to as “curl for humans”. Once installed, httpie is available as the http
command, which then folllows a syntax similar to the HTTP protocol itself:
http <METHOD> <URL> <HEADER>:<HEADER VALUE> <HEADER2>:<HEADER2-VALUE>
for example, this will display the response from bagvalueobjects.com:
http GET https://bagvalueobjects.com
By default, it will show the response headers and the response body, but this is easy to change using the -p
flag. The following will show only the request and response headers:
http -pHh GET https://bagvalueobjects.com
The value for -p
are H
(request headers), h
(response headers), B
(request body), b
(response body).
Request headers and body? Well, yes, you can send POST requests just as easily:
http -pHhBb POST http://httpbin.org/post foo=bar
You can see that we have a new argument at the end foo=bar
, this will send a JSON body with the value {"foo":"bar"}
. You can add as many properties as you like to the end of the command. You can also pass the -f
or --form
argument and it will send the key-value pairs as multipart/form-data
instead.
If you need to send complex JSON, use :=
instead, like so:
http -pHhBb POST http://httpbin.org/post foo:='["bar", "baz", "bat"]'
This will send the body {"foo":["bar", "baz", "bat"]}
.
There are tons of other options including being able to use files as the post body, send files, support for sessions, authentication and more.
gron
Many folks are familiar with jq
, a great command line utility for working with JSON, if you’re not familiar with it, I highly recommend that you check it out.
Sometimes however, jq
is just too complicated, or the result isn’t exactly usable. Sometimes, you just want to be able ack
(née grep
) some JSON for a specific value. gron
will break down JSON into valid Javascript assignments, for example, the simple body from our httpie example above might looks like this:
json = {};
json.foo = [];
json.foo[0] = "bar";
json.foo[1] = "baz";
json.foo[2] = "bat";
As you can see, this creates a variable json
, and assigns an empty object to it, it them sets the foo
key to an empty array, and then sets each of the numeric keys to it’s specific value.
Because it’s broken down to one assignment per line, you can now easily and reliable pipe it through ack or grep and find whatever you need.
A more practical example: list all the require-dev requirements in a composer.json files:
gron composer.json | ack require-dev
This will output the following:
json["require-dev"] = {};
json["require-dev"]["captainhook/captainhook-phar"] = "^5.23";
json["require-dev"]["captainhook/hook-installer"] = "^1.0";
json["require-dev"]["fakerphp/faker"] = "^1.23";
json["require-dev"]["infection/infection"] = "^0.28.1";
json["require-dev"]["larastan/larastan"] = "^2.0";
json["require-dev"]["laravel/pint"] = "^1.15";
json["require-dev"]["orchestra/testbench"] = "^8.0|^9.0";
json["require-dev"]["phpunit/phpunit"] = "^10.5|^11";
json["require-dev"]["ramsey/conventional-commits"] = "dev-allow-sf-7";
json["require-dev"]["roave/security-advisories"] = "dev-latest";
json["require-dev"]["symfony/var-dumper"] = "*";
We can then turn this back into JSON, and feed it into jq
to get the values using gron -u
or gron --ungron
:
gron composer.json | ack require-dev | gron -u | jq '."require-dev" | keys[]'
This will output:
"captainhook/captainhook-phar"
"captainhook/hook-installer"
"fakerphp/faker"
"infection/infection"
"larastan/larastan"
"laravel/pint"
"orchestra/testbench"
"phpunit/phpunit"
"ramsey/conventional-commits"
"roave/security-advisories"
"symfony/var-dumper"
Alternatively, let’s use gron
to remove any custom scripts from our composer.json. We can use this by again, piping the output through ack
, but this time using the -v
argument to exclude matches, and then passing it back to gron -u
:
gron composer.json | ack -v json.scripts | gron -u
The resulting JSON will be identical to the original, but with the entire scripts
key missing.
bat
The last tool I want to cover is a new addition to my local environment, and that is bat
, a replacement for cat
with syntax highlighting.
bat
has a few advantages over cat
besides syntax highlighting by default: the output is paged, includes the file name, and line numbers:
syntax highlighted code using bat
While bat
doesn’t provide as much utility as most of the other tools on this list, it’s simplicity makes it perfect as a drop-in replacement for cat
, allowing you to just add alias cat=bat
to your terminal configuration and forget about it.
Next Steps
If you want to try any of these tools for yourself, they are all available using brew
, which is available on all platforms.
This list was aimed specifically at improving your development workflows, however, I have also made many changes to my terminal environment as a whole which also aids me in getting my work done faster, and easier. If you want to hear more, let me know in the comments below!
Top comments (2)
Thank you for including ack! I use it all the time and it seems like no one has ever heard of it
tks for sharing