Ask HN: Best Command-Line Applications?

634 points by jaydouken ↗ HN
I really enjoy using a command-line interface instead of a graphical user interface, and was wondering if anyone had any solid recommendations for applications that one can use in a terminal window.

392 comments

[ 2.8 ms ] story [ 280 ms ] thread
I agree. A lot of them come with a UNIX system, although there are others. I use some of the moreutils stuff. For email, I use Heirloom-mailx. For text editing, I use vim. For database I use SQLite. For typesetting I use TeX. For processing pictures I implemented my own package called Farbfeld Utilities. For making MOD/XM musics, I wrote AmigaMML which uses a text file rather than the GUI that many other programs do. Hopefully other people on here can mention even more, because I am interested in the answer too, and probably my answer is insufficient to the original asker anyways.
A few of the ones I use almost daily

- Pandoc a handy document format converter: https://pandoc.org/ - Ripgrep, a faster grep: https://github.com/BurntSushi/ripgrep - There are quite a few prompt-toolkit based CLI which have been really nice: * mycli (https://github.com/dbcli/mycli), pgcli (https://github.com/dbcli/pgcli) * ptpython/ptipython (https://github.com/prompt-toolkit/ptpython) - Youtube-dl: http://rg3.github.io/youtube-dl/ - fzf a fuzzy finder for the console: https://github.com/junegunn/fzf - jq for JSON manipulation: https://stedolan.github.io/jq/ - Miller for CSV/TSV: https://github.com/johnkerl/miller

I would imagine you have already scoured the "awesome" lists: https://github.com/agarrharr/awesome-cli-apps#terminal-utili...

Thank you so much for posting that list, somehow it slipped under my radar. Great suggestions!
(comment deleted)
Wow. mycli and pgcli are so good!
It is. Omitting the semi colon to execute a statement alone feels good.
ptpython seems really useful, thank you! I was frustrated with the limited capabilities of the vanilla python REPL.
Maybe the best part of bash for me is AWK - so useful, and enjoyable to use. I use ffmpeg a lot for making movies from images, video conversion etc. I use Sage on the command line, mostly for programming in Cython and mathematical stuff with the Sage/Python REPL. It was 2.7GB (!) and comes with an absurd number of libraries and packages[0], mostly for maths and graphics. I started by using it in a browser notebook, but switched to the command line and never went back.

[0] http://www.sagemath.org/links-components.html

vim

It's really worth the time to learn. It's pre-installed basically everywhere, it's amazingly useful. It has the features of a modern text editor all in a command line.

Vim is an interactive application.
So are Midnight Commander, ranger, Mutt, tig, htop, emacs and many of the other great programs mentioned here.

I've taken this list to be of thing things that run in a terminal rather than strictly non-interactive programs.

I love watch.

  watch df -h
  watch ls -sh
  watch cat file
  watch nmcli device wifi list
  watch -n 10 --color curl -s wttr.in
always need to install watch and tree
I think I remember combining watch with tail before...not sure why since -f keeps a stream open.
Tail -f works by opening the file and remembering the byte offset, if it’s a log file that gets flushed/wiped then tail -f won’t see anything until the logs fill enough to exceed the previous file contents.
Unless you pass the option --follow=name in which case tail will if necessary reopen the file and follow it even when log-application has closed and moved it elsewhere and opened a new one of the same name.
True, but the `-F` flag will work in that case.
TIL

Works on BSD `tail` too. :)

My favorite use is:

  watch ps fx
I find it very soothing. :)
Wishing we could do this without polling, though ...
If you need to handle XML, xmlstarlet (http://xmlstar.sourceforge.net) is fantastic, and much more powerful than the standard line-oriented tools like sed and awk for this task.

Similarly jq (https://stedolan.github.io/jq/) for JSON data is great.

The only issue I have with xmlstarlet is that it can be sort of a pain when there are xml namespaces in the document. Most of the time, you just have to pass it the long option that ignores them all together
I'm not big on applications, period. Activities should be decomposed (or at least decomposable) into individual actions that I can stitch together in the shell.
I agree, we can use the pipes to put them together. That is how I do such thing, and design these programs, at least.

For example, one program is "playmod" which read a module music file from stdin, and write the raw audio data to stdout. The program "amigamml" is takes the MML code from stdin and write the module music file to stdout. And then, program "aplay" is playing the audio data from stdin on the speaker. Other example can be, "ls" to list files, "shuf" to put into a random order, and "xargs" to run another program for each one, and a shell script might then do "playmod" and "aplay", you can play the music at random!

Aren’t those individual actions still applications? I don’t know what you mean?
There's a frequent (but by no means universal) distinction drawn between "applications" and "utilities". In the former case, you have repeated interaction with a single process, typically with some measure of "ownership" of its display port. On the other hand, a utility typically does a single thing, produces some output, and then exits.
For working on servers, tmux + mosh is a killer combination: mosh makes your connection resilient to network issues and tmux gives you (back) scrollback and cross-session persistence.

mutt is hard to beat as an email client and circe (an emacs package) + znc on a digital ocean instance or equivalent makes for a great persistent irc session.

Mosh also makes it possible to have an ssh client running on a mobile device and still use the mobile device as a mobile.
Another vote for tmux + mosh combo.
Music organizer/player http://beets.io

File browser https://github.com/ranger/ranger

Emacs - It does anything you want.

Emacs If you like vim keys bindings - http://spacemacs.org

Terminal multiplexer - Tmux

Another alternative to Emacs with vim keybindings is Doom Emacs. It's superior to Spacemacs imo.
I've been using Spacemacs for a while, what sets Doom Emacs apart?
I am a convert from Spacemacs to Doom, and I have found that one of the main differences that sets Doom apart is easier configurability than Spacemacs. In Doom, there is still the concept of "layers," but IMO it is much easier to figure out what the layers are doing and customize them from there.

Also, I have found Doom to be much quicker (takes about 2 seconds to load, not using server/client) and less buggy than Spacemacs. I would highly recommend giving Doom a try!

This. Also, the developer is responsive on his Discord server should you have any issues with the editor. Henrik is patient, kind and reliable, rare traits for open source projects these days.
I completely agree, I have had a very similar experience with Henrik.
Beets is really great, before switching mainly to streaming I used it every day to tag new additions to my library.
youtube_dl an ffmpeg would be my top two in terms of power.

Here are my top commands by frequency of use:

    4421 git
     952 open
     936 vim
     908 cd
     603 ls
     566 grep
     533 cp
     429 rm
     414 mv
     250 atom
     247 pip
     233 mkdir
     223 fab
     163 docker
     130 touch
     128 find
     123 youtube-dl
     113 python
     103 ssh
     100 cat
      99 wget
      81 pytest
      75 brew
total is of ~16k history lines... this means one in ever 4 commands I type is git! Wow I didn't know that. Probably `git status`...
I use git so much that I made these aliases in zsh:

    alias g="git show"
    alias gh="git show HEAD"
    alias gs="git status"
    alias gl="git log"
    alias gco="git checkout"
    alias gd="git diff"
    alias gbl="git branch -v"
    alias gbd="git branch -D"
    alias gri="git rebase --interactive"
    alias grc="git rebase --continue"
    alias gra="git rebase --abort"
    alias gst="git stash"
    alias gsta="git stash apply"
    alias gx="gco -- \*; git reset HEAD \*"
    alias gcp="git cherry-pick"
    alias gcpc="git cherry-pick --continue"
    alias gcpa="git cherry-pick --abort"
A few hundred instances of "gs" in my .zhistory :)
I find that...

    alias glol="git log --oneline"
...comes in handy as well, and it's fun to type.
Try this one sometime...

  alias lg = log --date=format:'%Y-%m-%d %H:%M:%S' --pretty=format:'%cd %<(20,trunc)%an %C(auto)%h%Creset%C(auto)%d%Creset %s'
I find my git graph, git save, and git lint (also, git fetch --prune but lo alias for that one) extremely useful.

Aliases in my ~/.gitconfig:

    [alias]
        co = checkout
        cm = !git add -A && git commit
        br = branch
        ci = commit
        st = status
        unstage = reset HEAD --
        recent = for-each-ref --count=10 --sort=-committerdate refs/heads/ --format="%(refname:short)"
        overview = log --all --oneline --no-merges
        recap = !git log --all --oneline --no-merges --author=${1-$(git config user.email)}
        today = !git log --all --since=00:00:00 --oneline --no-merges --author=${1-$(git config user.email)}
        changelog = !git log --oneline --no-merges ${1-$(git describe --abbrev=0)}..HEAD
        upstream = !git log --oneline --no-merges HEAD..${1-$(git branch -lvv | perl -ne '/^\\*.*\\[(.*?)\\]/ and print "$1\n"')}
        local = !git log --oneline --no-merges ${1-$(git branch -lvv | perl -ne '/^\\*.*\\[(.*?)\\]/ and print "$1\n"')}..HEAD
        graph = log --oneline --graph --all --decorate --date=iso
        save = !git add -A && git commit -m 'SAVEPOINT'
        undo = reset HEAD~1 --mixed
        backup = !git push origin/backup/$(whoami)/$(git branch)
        lint = !git branch --merged | grep -v \"^\\s*master$\" | grep -v \"\\*\" | xargs -n 1 git branch -d
Thanks for the tip.. :)
nice ones! couple from my bash_alias

    alias ..="cd .."
    alias ..2="cd ../.."
    # ... you get the idea, mine goes up to 5
    function mkcd () { mkdir -p "$@" && eval cd "\"\$$#\""; }
    alias h="history|grep"
Instead of your `..` aliases, I have this, which saves some copy-pasting.

    function up() { cd "$(printf '../'%.0s $(seq 1 "${1:-1}"))" && pwd; } #up 4 goes up 4 directories

    alias ...="cd ../.."
    alias ....="cd ../../.."
hahah I have gs and gb(branch), just because I'm just constantly typing them(sometimes for no reason at all), others I end up typing the full commands tho
I’ve been using short aliases for my most frequently used git commands for a few years now. I can’t imagine not using aliases.

  alias st='git status'
  alias dp='git diff'
  alias di='git diff --cached'
  alias aa='git add -A'
  alias cm='git commit -m'
  alias pu='git push'
Having these aliases of mine makes these actions something that you don’t need to spend any mental effort to perform at all.

I highly recommend others to define aliases that make sense to them for the most used got commands.

Mine are named the way they are because the two letter alias represents how I think of the action that the command performs:

* st - status

* dp - diff pending

* di - diff

* aa - add all

* cm - commit

If you define your aliases this way (speaking to the other readers of this thread, not the person I am replying to), you will find that the combinations become muscle memory quickly.

Notice also that unlike a lot of other people including the person I am replying to, my aliases are not prefixed with “g”. Again this boils down to your personal way of thinking. I’ve used other version control systems before, switched to git several years ago, and use git pretty much exclusively. I am of course aware at all times that I am working with git, but at the same time when I think of actions to perform, I don’t think of them as “git this or that”, I only think of the “this or that” part. If that makes sense :P

But yeah, find aliases that work and make sense for you.

I use of few of these as well as alias stage="git add -A && git status" alias unstage="git reset HEAD && git status"
gitsh - https://github.com/thoughtbot/gitsh

Since git is by far the command a lot of people type the most, this shell comes in really handy. It supports all regular git aliases, has autocompletion, and you can set default commands to be run when you just press return. It's amazing how much typing it saves.

+1 to Gitsh. Feels like it saves a massive amount of typing.
httpie + jq is a great duo for exploring and manually probing APIs.

Gron (grep JSON) is handy when you get a massive API response and quickly need to figure out what subkeys interest you.

The silver searcher (ag) is my go-to code search tool. I'll have to try ripgrep to compare.

Pass is neat for injecting personal secrets into bash scripts securely.

Some of my favorites, apart from the obvious ones like Vim/Emacs and common Unix utils...

    notmuch - email database 
    ncmpcpp - MPD frontend (music player)
    taskwarrior - task and time management
    mutt - email
    ranger - file manager
    pass - password manager
If you aren't using tmux or screen, you probably should be, especially over SSH sessions. They allow you to have multiple consoles open and switch between them, split window, and disconnect from SSH and then reconnect with all your things still open and running (as long as the server stayed running).
I use some scripts around screen (and tmux would do the job at least as well, just haven't had reason enough to switch) to manage contexts for my shells. The key is that that process will be the parent of any shells I spawn in contained windows, and so if I set an environment variable (I use SESSION) before kicking off screen it will be inherited, and visible in my bashrc. This lets me set up a lot of context specific things - path and functions and aliases - but the single best thing about it is a separate bash history per context.
I have a EC2 instance who's main purpose is to run a screen session. I ssh to my EC2, and load that screen. I have every server I manage in it's own "window" inside this screen. I run screen on each of these machines, so I can hop between inner and outer screens.

The main screen instance is started with:

screen -S outer_screen

I then create a screen session for that EC2 with

screen -S inner_screen

I pop open new screens with this handy command:

screen -S outer_screen -X screen -t newmachine ssh user@newserver.example.com

As someone who hasn't invested much time into tmux/screen, what are the benefits of it over just using eg; multiple terminal tabsn or using the terminal's built in split windowing? I'm sure there's probably a benefit but I dunno what it is
It persists your session, so if you get disconnected you can just log in again and 'tmux attach' to resume from where you left off. Any long running commands will still be running.
Both tmux and screen allow you to attach/detach. Thus you can log off, and you can pick up your session later.

For example, yesterday I logged into a Linux server at DigitalOcean via SSH. I ran tmux, started a long-running job, detached the session. I closed my laptop to go home for lunch. When I returned at my desk, I logged into the server and reattached the tmux session so I could see the results.

If it's all on one device and no networking, I don't know of any great benefit. But if you sometimes connect to the machine remotely then Tmux allows you to pick up an existing session, e.g.

You open tmux on your desktop, open some command line things, then walk away and pull out your laptop or desktop, SSH to your computer, "tmux attach" and have the same session open - and it's open on both devices, both seeing the same updates at the same time, like a terminal-vnc.

And you can variously use them to allow two separate users to share the same session, either one controlling and others read-only, or multiple-editing ( https://unix.stackexchange.com/questions/2523/what-are-other... )

I agree with everyone else that it's great on remote systems, but the reason I use it locally too is because I can set up all a project's "tabs" with just one command. I have dozen-line scripts for each client/project that will either create or attach to a tmux session, and when creating set up all the windows how I want: setting their names, cd'ing, opening psql, tailing a log, changing the bottom color (green for development, yellow for staging, red for production), etc. For Rails work I typically have separate windows for models, controllers, views, stylesheets, and javascripts. It makes it really easy to get started after a reboot, or just hide projects for a while and bring them back quickly.
occasionally i need to restart the GUI. using tmux locally is very helpful for that. also sometimes i log into my workstation from remote, like when i am travelling. it's nice to be able to access the running session.
One useful reason to use it over a terminal is portability. If you're happy mostly working in the terminal then tmux will be the same on every OS your work on even if your favourite terminal isn't available.
rsync. It’s installed everywhere and makes it super easy to keep source code in sync between laptop and remote servers. It’s so fast that I completely ignore more advanced solutions based on fanotify or similar, and literally include rsync before every “build/run” command during development.
rg (ripgrep): https://github.com/BurntSushi/ripgrep

I used to use ag (the silver searcher) [1] before, and `ag` was practically a muscle memory to me, but then I came across ripgrep and it was so much faster. I've now installed a static binary of ripgrep in every machine I have SSH access to.

[1] https://github.com/ggreer/the_silver_searcher

The first time i use it, I was in shock about how fast ripgrep is. Amazing.
Note that rg and ag don't have the same feature sets. Here's a handy chart that shows the differences.

https://beyondgrep.com/feature-comparison/

* fish - essential prerequisite in order to live in the command line

* autojump (aka j) - for changing directories quickly

* open - required to interact with the non-cli world, ships by default on macOS and here's one for Windows/WSL: https://github.com/neosmart/open

* imgpaste - for pasting screenshots into a PNG or JPEG directly (https://github.com/neosmart/imgpaste)

* pbpaste - for pasting into the shell (or if you're on Linux or Windows: https://github.com/mqudsi/fish-config/blob/master/functions/...)

* fzf - a general-purpose "selector" ui for choosing "things" from a list based off, such as your history (bound to ctrl+r) or files in a directory (bound to ctrl+p with input generated by bfs or fd)

* neovim - my configuration here: https://github.com/mqudsi/nvim-config

* ripgrep - for finding strings in files

* fd - for finding files quickly

* sed (with -r) - insanely powerful for common string operations

* tr - lets you deal with line endings, which sed can't

* youtube-dl - download youtube videos from the CLI

* curl/httpie - (scriptable) network requests

* aria2c - high-speed (multi-threaded) downloads and torrent downloads, it just works

* jq - for manipulating json in shell scripts

* ncdu - find space taken up by directories/files, but it's aging and in need of a dire rewrite like fd/rg did for find/grep

* pbedit - edit the contents of the clipboard in your favorite editor https://github.com/mqudsi/fish-config/blob/master/functions/...

* weechat - irc in your command line

* ffmpeg - except I am much more likely to use it via one of the wrapper fish scripts I've written such as ffencode, fftrim, ffconcat, ffmute, etc. because it is (necessarily) so damn verbose and infinitely tunable.

* tmux - if I'm working remotely or on a headless machine where I can't just ctrl+shift+n to open a new terminal window (which I prefer)

> tr - lets you deal with line endings, which sed can't

I'm not sure what you mean by "deal with line endings", but sed can operate across multiple lines.

https://www.gnu.org/software/sed/manual/html_node/Text-searc...

Maybe is meant you can remove the carriage returns easily, in case you want only the line feed on the end of the line.
I mean directly operating on the line ending itself. e.g. remove all lines or replace `\n` with the record separator, etc.
Like so?

    % echo 'one\ntwo\nthree' | sed -e 's,$, four,'
    one four
    two four
    three four
No, like this:

    > echo ‘one\ntwo\nthree’ | tr \n \|
    one|two|three
echo -e 'one\ntwo\nthree' | sed -ze 's/\n/|/g'
Forget tr/sed, just use `perl -i.original -pe`
On bare-bones unixish systems, you’ll be more likely to find sed/tr than Perl (for me, a clean FreeBSD install).
fzf is awesome. I use it in vim and bash.

https://www.tecmint.com/fzf-fuzzy-file-search-from-linux-ter...

----

I use the Silver Searcher all the time. Very fast.

https://github.com/ggreer/the_silver_searcher

----

tig, a text mode interface for git.

https://github.com/jonas/tig

It's been mentioned previous, but you should check out ripgrep - it's even faster than Silver Searcher a lot of the time

https://github.com/BurntSushi/ripgrep

Does anyone not working on million-line codebase ever find themselves limited by grep? I am genuinely curious.
Do you mean more or less than 1M LOC?

grep is usable on very large code bases, because after the first scan, all the sources are loaded in the file system cache, so the successive grep are done in RAM and are very fast.

So much so that I almost never use ctags despite the improved semantic search (you can find more easily the exact identifiers and distinguish them by category). grep is just as fast and precise enough.

Unfortunately, I work on a million-line codebase.

Grep might be fine 99% of the time, but there's no reason to not drop a ripgrep binary on every machine I use regularly.

Ripgrep is faster across the board and has better defaults for working in Git repositories. Since I'm working with a large codebase managed in Git, it's a no-brainer.

* tldr - better than man in 80% of cases

* htop - better version of top for multi-core machines

* tmux - when you want to run long-running commands

If I had to pick a single utility, it would be pv[0]. It's very simple, but I find myself using it all the time. Basically you stick it in a pipeline of commands to get a progress bar. The simplest usage is just to replace cat or input redirection with a call to pv. Saves a lot of time when I can quickly find out if the command I wrote is going to take 30 seconds or 30 minutes.

https://www.ivarch.com/programs/pv.shtml

I guess these are so obvious no one mentioned them, but: ssh, git, zsh, bash, curl, wget, gpg, gzip, xz, btrfs, qemu, pv, tar, diff, comm, column, sort, uniq, sed, bc, tr, od, xxd, tcpdump, tshark, ping, nmap, ip, iw, xdotool, xrdb, grep, pgrep, pkill, lsof, inotifywait, journalctl, systemctl, convert, ed, and probably countless more I'm taking too much for granted to remember.
For sysadmin needs:

  - htop (better top)
  - nload (network traffic visualization)
  - nano (I know, but works great for simple editing)
  - curl (http everything tool)
  - telnet/nc (check listening ports)
I hate that nano is so looked down on. I use it too and it's a great tool. I don't feel any shame using it.
nethogs - Can show bandwidth per process.