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 6 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