Published at
Updated at
Reading time
3min

Use at your own risk. πŸ€“ Before implementing any functionality that makes running copied code easier, be aware that the internet's a bad place. There's always a chance that a command has malicious intent or even includes hidden commands.

I just saw an npm package that makes copying and pasting of shell commands easier. Documented shell commands often include a leading $ character (e.g. $ npm install whatever) to signal that the code block is a shell command. And when you're like me, you always copy and paste the $ sign with the command, leading to a command not found: $ error in your terminal.

Shell session: $ npm install whatever / zsh: command not found: $

And while it's not a huge deal, you have to either carefully copy the command not to include the $ sign or paste the command into your terminal and remove the dollar manually. There has to be a better way...

... and that's where the mentioned npm package comes into play. The package provides a global $ command that behaves like a proxy on your command line. The $ command simply runs all passed-in arguments.

$ echo "hello world" leads to an executed echo "hello world". $ ls is basically the same as ls. You get the idea. πŸ™ˆ

This command is one of these tiny adjustments that makes a terminal feel like home. But what if I told you that you can create the same functionality without npm packages or Node.js using two lines of shell scripting? Read on!

Two lines to run commands with a leading $

Let's start by adding a new shell command to your system. Have a look at your $PATH configuration. The $PATH environment variable defines where executable files are located on UNIX systems.

That's the shortened version of my machine's $PATH. πŸ‘‡

$ echo $PATH

/usr/local/bin:/usr/local/sbin:/Users/stefanjudis/bin:/Users/stefanjudis/.bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

$PATH is a long string that separates all different locations by a :. And as you see, I have various bin directories. All my custom commands are placed in my home's .bin directory – ~/stefanjudis/.bin. I chose this location because I don't want to mix system and custom commands (ls, cat, etc. are located at /bin).

Choose a directory to place your new command.

$ pwd
/Users/stefanjudis/.bin

$ ll
.rwxr--r--  14 stefanjudis  8 Dec  2020 -- $
.rwxr-xr-x 413 stefanjudis  2 Aug  2020 -- git-delete-branch
.rwxr-xr-x 183 stefanjudis 19 May 22:03 -- git-pr-select
.rwxr-xr-x 538 stefanjudis 17 Dec  2020 -- git-select

Create a new file named $ in this directory. Yep, that's right, this file doesn't include a file extension or something – it's really just a dollar.

Make sure the file is executable using chmod 755 $.

If you haven't used the chmod command before, make sure to read up on "UNIX file permissions".

The file's content is two lines:

#!/bin/zsh
exec "$@"

The first line is called a Shebang and defines what program should be used to interpret this file when you run it as a standalone command. In my case, it's the zsh binary – #!/bin/zsh. #!/bin/bash works fine, too.

Then, exec "$@" runs and expands all the passed-in parameters. And that's all the magic already!

Make sure to include the quotes around $@ to avoid parameter expansions.

With this one file containing two lines, you can now run $ echo "hello world" and all these "dollar commands" in your terminal. πŸŽ‰

Terminal command: $ echo "hello world"

Happy copy and pasting!

Edit: Gonçalo Morais tweaked the $ script and added a confirmation dialog. Great work!

Thanks to "okdjnfweonfe", Peter Franken and Joe Block for providing some feedback on the initial script. πŸ™‡β€β™‚οΈ

Was this post helpful?
Yes? Cool! You might want to check out Web Weekly for more web development articles. The last edition went out 10 days ago.
Stefan standing in the park in front of a green background

About Stefan Judis

Frontend nerd with over ten years of experience, freelance dev, "Today I Learned" blogger, conference speaker, and Open Source maintainer.

Related Topics

Related Articles