The most useful bash commands for front end development

Whether it’s just for npm install or some git commands, most everyone deals with bash sometime. I’ll be honest, bash can have some weird syntax, but I still think it’s a highly useful tool and very efficient way to automate tasks. For example, react, angular, and vue all have shell scripts in their repositories. Plus, bash is available on every commonly used operating system now—it comes with macOS, most Linux distros, and now Windows via the new Linux sub-system stuff.

I’m no expert in bash, but whenever I’ve invested time into learning more about it — whether it’s just a few commands or it’s syntax, it’s always paid off for me. So I’ve compiled a list of commands or other things I’ve learned about bash that I’ve found consistently useful.

Navigating around

You’re probably familiar with cd (change directory), but it can get cumbersome if you want to go to a folder, run a script, and come back to where you are. pushd allows you to navigate to a directory, do work there, and then popd back to where you were originally without having to remember the path back there (like cd ../../..).

pushd level-1/level-2
# do work ...
popd
# now we're back to the directory we started in

Quickly peek inside a file

Let’s say I just want to view a file’s contents quickly. There’s a few options for this. The easiest is cat which stands for concatenate but can be used to just print the contents of a file.

For example, I want to check something in the package.json file:

cat package.json

That prints the entire file out for me in my terminal window.

Note (in case you’re pretty new to bash/shell stuff): For the above command to work, you need to be in the same directory as package.json. Also you don’t need to type out package.json completely, start typing and then hit the Tab key as you go to get autocomplete.

Now let’s say it’s a huge file and we don’t want the whole thing printing out and cluttering the screen. Let’s use less for that:

less server.log

That’ll show the file in a scrollable overlay thing in your terminal window. Less doesn’t load the entire file into memory, so it’s fast 😎. But when you’re checking out your huge server.log file, for example, you probably care more about the end of the file than the start, right? Use the Shift+G shortcut to jump to the end of the file, and then scroll up from there. Exit less with q. To search for text in the current file when in less , you can search for text by inputting /your search here and hitting Enter .

Opening files and folders

Now let’s say we looked at a file, and we want to open it in an application.

open index.js

open will open the file in the default application you have associated with that file. In my case, that’ll open it in my current VSCode window. Maybe we’re opening a weird file that’s not associated with any application in particular.

open yarn.lock

For me this returns: “No application knows how to open yarn.lock.” Let’s tell bash where we want it opened:

open yarn.lock -a TextEdit

Or open yarn.lock -a "Visual Studio Code" but that’s a lot of typing. However, if you want it in VSCode quick and easy from the command line, you can install VSCode’s command line tools and run code yarn.lock.

Another cool open trick is it can open the current directory (or any directory) in Finder:

open .

Or replace the . , which means the current directory, with whatever one you want. If you’re on a Windows bash emulator like Cygwin or git bash, explorer . does the same thing, but in Windows Explorer. This is especially handy for hidden folders you can’t get to in the UI, e.g. open .git .

Create and delete directories and files

This is bread and butter bash, so you use this all the time. So, let’s create a directory with mkdir.

mkdir my-folder

Cool, I love how you just created that folder for me, bash. Now let’s create folders several levels deep and let bash handle creating ones that don’t exist as it goes.

mkdir -p level1/level2/level3/level4

Without the -p , mkdir will fail on non-existent directories. Now let’s delete them all with rm.

rm -rf level1

The -r stands for recursive and the -f for force. That way bash knows to delete everything in that directory and everything below it and not to prompt me for confirmation when deleting files.

Now let’s create an empty file. There’s a few ways to do this. I usually use touch.

touch myfile.js

But I just learned that good ol’ echo does the job even better (I think).

echo > myfile.js

That creates an empty file, which is nice sometimes. (You can read up on how the angle bracket operator works here). Now let’s create a file and initialize it with something.

echo "console.log('hey hey')" > index.js

Oh, nice.

Finding files and searching text in files

You’re trying to find that one file, what was it called again?

find . -name "*part-of-the-filename*.js"

The name parameter isn’t a regex, but it accepts and matches on some special characters, like the wildcard *.

You can tell find to do stuff with the files it finds too. Let’s say I need to delete a bunch of log files. find makes this easy.

find . -name "*.log" -delete

Now, let’s say I want to move all my unit test files to a separate folder, for some reason.

find some-folder -name "*.test.js" -exec mv {} tests \;

The -exec param takes an arbitrary command, executes it for each file it found, and substitutes {} with the filename. -exec has to end with a ; , which has to be escaped, hence the \; weirdness at the end. The syntax is weird at first but when you do it a few times, you forget about it and just appreciate how fast that was compared to using the UI or writing a node.js script to do it.

In order to find content in files, we can use grep. Grep can get complicated with lots of flags quickly, but this is fairly simple and useful:

grep . -Re "regex pattern here"

That recurses (-R) from the current directory and searches all files for a regex match (-e standing for regex pattern). That outputs the file the match was found in as well as the text it matched. Grep gets more useful if you add more flags to it. Let’s tells it to output the line number in the file the match was found on, ignore case, and colorize the match. So if I wanted to find all instances of require('lodash') or require("lodash/debounce") in a project:

grep -Rnwi -C 1 --color . -e "require(.*lodash.*)"

…but that’s a lot of typing, which leads me to my next point…

Alias long commands

Let’s alias that last grep command. Open your bash_profile (usually located at your user home directory, ~/.bash_profile , you can create it if it doesn’t exist) and add to that file:

alias codegrep="grep -Rnwi -C 1 --color . -e $1"

The $1 gets replaced with the first argument that you pass when you invoke the alias. Now we can codegrep "require(.*lodash.*)" and it works just the same as before. Cool.

One of the most useful aliases that I have is this one:

alias json="cat $1 | python -m json.tool"

That takes a JSON string and formats it using Python’s json.tool (Python is shipped with macOS, no installation necessary). For example:

curl https://pokeapi.co/api/v2/pokemon/1/ | json

Much easier to read than the wall of unformatted JSON string that you get without it. (You can read up on the pipe operator | if that’s new to you).

History

Forget a long command that you did last week? Bash saves every command you run in a history which you can access via history. So maybe you ran a complicated webpack command using the webpack-cli and can’t remember it.

history | grep webpack

You can grep your bash history to quickly find it. Note that your history is capped, so anything too old gets dropped off the list.

Kill runaway processes

Maybe you started a node HTTP server that’s listening on port 9000 and you thought you closed it out, but when you try to start a new server at port 9000 you get an “address in use” error (EADDRINUSE). So somehow it’s still running somewhere?

First, let’s find the process id that is listening on that port with lsof.

lsof -i:9000

That’ll output a little table that includes the process id. Now let’s shut down the process with the aptly named kill.

kill <process id here>

This might seem esoteric but it’s come up for me a number of times. Just skip this if it’s never happened to you.

I forgot some flags for this command I’m trying to run

Luckily, you can access bash’s manual from bash itself.

man <command name here>

This brings up a less like window overlay thing with all the documentation and usually some examples for the command. man stands for manual. Even faster than googling.

Create a script out of some bash

Let’s say you have a recurring task you’ve automated with some bash. Let’s create an executable bash script and then run it from the command line.

First, let’s create our script file (do this however you want).

echo "echo hello from bash" > script.sh

Now we need to be able to execute this file from bash so we need to change permissions.

chmod +x script.sh

Now let’s run it

./script.sh

The dot slash tells bash to evaluate and run your script as if it had been typed out from your terminal.

Repeat last command with sudo

You’re trying to add an entry to /etc/hosts or something which requires privileges. Your command doesn’t work without sudo , but instead of retyping it all out, you can just sudo !! .

Background tasks

Sometimes I rm -rf a huge folder (like node_modules or something) and then sort of regret it because now that terminal tab is locked up until that command completes. Luckily, backgrounding tasks in bash is easy.

rm -rf node_modules &

The & tells it to execute in the background, so after you run that, your shell will immediately return control to you so you can keep working. It’ll notify you when it’s complete too.

The same & operator can be used to parallelize tasks. Let’s say in a script we want to do two things that take a long time but can be run in parallel.

zip -r big.zip large-dir &
zip -r big2.zip other-large-dir &

Conclusion

Spending a little time to learn bash is time well-spent, even for a front-end developer. This list, by the way, is in no way exhaustive, as there’s so much you can do with bash. These are just the commands I’ve found myself reaching for the most. To recap them all in order:

  • pushd
  • popd
  • cat
  • less
  • open
  • mkdir
  • rm
  • touch
  • echo
  • find
  • grep
  • alias
  • history
  • lsof
  • kill
  • man
  • chmod

Happy bashing 😁.


Side note: How are all these shell commands implemented?

This probably depends on lot on your operating system. Most of the bash commands I referenced above that aren’t shell “built-ins” (like cd) can be found here in GNU’s coreutils repository and are implemented in C. I imagine most implementations look like those. Of course, anything in /bin (among other directories), can be executed as a command from bash, and can be implemented in any language you like. It’s also worth noting that many bash commands are just a CLI for C API functions (like mkdir).