A short story on npm scripts & killing processes (how to make your tools work for you!)
Tags: bash, npm, productivity
Published: 2020-08-23 06:46:42

# The background

I have a project. It has static files. They are:

* A HTML file

* A Sass file (.scss)

* A Typescript file (.ts)

To get my sass to compile into regular .css, I use the `node-sass` npm package.

To get my typescript to compile into regular .js, I use the `tsc` compiler.

To get my browser to automatically update whenever one of these files is changed, I use the `browser-sync` npm package.

### How I start up:

* Open a terminal. Go to project directory. Start `vim`.

* Open another terminal. Go to project directory. Run `tsc & node-sass & browser-sync &`

	- (Full disclosure: `node-sass` and `browser-sync` are run with options, but that's not important)

* Go back to vim and edit.

### How I close down:

* Close vim (*but how?!*). Close terminal.

* Go to the other terminal. Find and kill my processes, one-by-one:

	- `ps aux | grep node-sass`

    - Mentally take note of the displayed PID (process ID) from the second column

    - `kill <PID I definitely always remember perfectly>`
    - Repeat for `tsc` and `browser-sync`

This is clearly a lot of typing and PID-remembering. Nobody likes that. We can do better.

---
# The npm script

My start up command is too much typing. So we’re going to have `package.json` do the heavy lifting.

```
“scripts”: {
  “ts”: “tsc”,
  “sass”: “node-sass”,
  “browser”: “browser-sync”,
  “serve”: “npm run ts & npm run sass & npm run browser &”
}
```

Now, all we have to run is `npm run serve` and everything is taken care of for us.

OK, but why go through all the trouble of making scripts for each single command? Why not just do:

```
“scripts”: {
  “serve”: “tsc & node-sass & browser-sync &”
}
```
The answer to that is all about our friend, `&`, the ampersand. Anything with an `&` will run continuously and show up in the output of `ps aux`. And we intentionally want all of our processes- whatever they really are- to show up as `npm` processes!

Hence:

* The `“serve”` script that only runs `npm` commands

* The absence of an `&` in the `“ts/sass/browser”` scripts

---
# The kill

So here’s why we want all of those tools to show up as `npm` commands:

`ps aux | grep [n]pm | awk ‘{ print $2 }’`

This command:

* Outputs all processes

* Filters by `[n]pm` (only considers processes with the first letter of “n”)

* Grabs the second column/word of output, which in this case is the PID

Now all that’s left is to kill all of those PIDs we collected:

`kill $(ps aux | grep [n]pm | awk ‘{ print $2 }’)`

Booyah. But… hate typing that? Me too. So, we can either just alias this in our .bashrc as ‘npmkill’ or something…

---
# The generalized, easy to type kill

…or take an extra minute to whip together a quick bash script that:

* Accepts a grep search term

* Lets us see our processes before we kill them

```
#!/usr/bin/bash
ps aux | grep $1

read -p ‘kill processes? (y/n): ‘ confirm

if [ $confirm == ‘y’ ]
then
  kill $(ps aux | grep $1 | awk ‘{ print $2 }’)
fi
```

The `$1` refers to the first argument passed to the script, so if we call our script `pidkill.sh` then running `pidkill [n]pm` would mean `$1` == `[n]pm`.

The `read -p ‘<prompt>: ‘ confirm` allows us to (a) enter our response on the same line and (b) saves our response to the `$confirm` variable.

Then it’s a simple if statement and our shell expansion!

Don’t forget to alias your script in .bashrc if you want to be able to use it anywhere, otherwise you’ll have to be in the directory of the script or type out its path every time.

`alias pidkill=’~/pidkill.sh’` does the trick for me.

**Thanks for reading and happy coding!**

**sponge**