While I understand why you're trying to do what you do, but honestly, I'd really avoid masking something as critical as a sigil. Before you know it, you'll end up doing something similar for #
(as some commands out there assume you're running them as root). That's just going to be a mess.
What you could do instead, is write a script that processes (and if needed) trims whatever is in your clipboard. I'm going to assume you're running some flavour of Linux for the purposes of simplicity. There are similar utilities for OSX, so if needed you can just modify the approach suggested here to fit your system.
Simple and risky
Apart from what you already have, install xclip
, a command that allows you to interact with your system clipboard from the command line (e.g. xclip -selection c file.txt
saves contents of file.txt to clipboard).
Now xclip
can also print out (and as such access) whatever is in your clipboard by running xclip -o
or xclip -out
, so let's start with that:
#!/usr/bin/env bash
str="$(xclip -o)"
Great, so now str
contains whatever is in your system clipboard. Now if you've accidentally selected the leading $
, chances are you've accidentally selected the space before it, or maybe even a line-break. To be safe, it's probably best we trim the string in question. There's ways to do this with bash's many weird and wacky string manipulation constructs, but keeping it simple, we can just use xargs
which, if no other arguments are provided, will trim the input string and return it as-is:
str="$(xclip -o | xargs)"
OK, so now we can check to see if the string in question starts with a $
:
if [[ "${str:0:1}" == '$' ]]; then
str="${str:1}"
fi
So if the first character of our string is $
, we're cutting it off, and setting str
to be equal to str
minus the first character, getting rid of the dollar sign. You could add something like:
if [[ "${str:0:1}" == '$' ]] || [[ "${str:0:1}" == '#' ]] ; then
str="${str:1}"
fi
To account for the aforementioned leading #
characters you may have accidentally copied. At this point, you're ready to do what you're currently doing:
## Either using eval:
eval $str
## or the shorter, but equally risky
$str
Make the script executable and call it something short and to the point:
$ vim ~/bin/execpaste
#!/usr/bin/env bash
str="$(xclip -o | xargs)"
if [[ "${str:0:1}" == '$' ]] || [[ "${str:0:1}" == '#' ]]; then
str="${str:1}"
fi
echo "Executing ${str}..."
$str
Make the script executable ($ chmod +x ~/bin/execpaste
), and add ~/bin
to your path (rather than adding scripts directly to /usr/bin
) by adding this to your .bashrc
or .profile
file:
export PATH="${PATH}:${HOME}/bin"
Slightly less risky
Personally, though, I prefer to be able to see what I'm pasting in my terminal before executing it. Just to be sure... In that case, I'd keep the first part of the script, but call it prepclip
or something (short for prepare clipboard). Most of it would remain the same, apart from the last part (where the command is actually executed). I'd just write it back to my clipboard instead:
#!/usr/bin/env bash
str="$(xclip -o | xargs)"
if [[ "${str:0:1}" == '$' ]] || [[ "${str:0:1}" == '#' ]]; then
str="${str:1}"
fi
# send updated string to clipboard
echo "${str}" | xclip -selection c
In terms of actually using this script, it does indeed take 2 steps:
$ prepclip
$ <paste>
But the second step, to me, is a worthwhile sanity check.
MacOS
MacOS, as far as I know has 2 commands to paste and copy that you can use instead. Below is the MacOS version of the last script (cleaning up clipboard input and writes in back to the clipboard), just in case you're on MacOS:
#!/usr/bin/env bash
str="$(pbpaste | xargs)"
if [[ "${str:0:1}" == '$' ]] || [[ "${str:0:1}" == '#' ]]; then
str="${str:1}"
fi
echo "${str}" | pbcopy
That should give you everything you need, without messing with sigils.