DEV Community

Cover image for Better Copy and Paste in WSL with Two One-Liner Aliases
Emmie Päivärinta
Emmie Päivärinta

Posted on

Better Copy and Paste in WSL with Two One-Liner Aliases

Don't you hate it when the JSON document copied from the terminal doesn't work because of extra newlines? Or getting a syntax error because the string you pasted into the terminal needs to be escaped?

Before getting a Windows laptop a while ago I primarily used macOS for over a decade. From macOS, I'm used to having the convenient pbcopy and pbpaste command-line tools for copying and pasting in the terminal. Not only do they sidestep these problems, but they also make it a breeze to use almost any command-line tool together with the clipboard.

So understandably, I felt bummed out when I started using WSL to run a Linux shell inside Windows and realized it doesn't come with similar clipboard tools. Luckily, we can easily add our own pbcopy and pbpaste commands to WSL with a couple of one-liner command-line aliases.

Getting Started

We're going to define two aliases in our WSL Linux shell. pbcopy sets the clipboard contents from its input, and pbpaste outputs it. Creating aliases in the shell is done with the alias command:

alias pbcopy='powershell.exe -Command "Set-Clipboard -Value \$input"'
alias pbpaste='powershell.exe -Command "Get-Clipboard"'
Enter fullscreen mode Exit fullscreen mode

The aliases can be used immediately, but will only last until the end of the session. To make sure they'll always be available, we need to add them to our shell configuration file. The configuration file lives in the home directory (~), but the filename depends on the shell. For Bash this file is called .bashrc, and for ZSH it is .zshrc. The changes will only take effect after starting a new shell.

Let's put the aliases to the test with some commands. First, we'll get a random UUID by copying the output of uuidgen with pbcopy:

uuidgen | pbcopy
Enter fullscreen mode Exit fullscreen mode

Then, let's use a copied JSON document as the body of an HTTP POST request by piping the output of pbpaste to curl:

pbpaste | curl -H "Content-Type: application/json" -d @- https://httpbin.org/post
Enter fullscreen mode Exit fullscreen mode

By simply defining two short command-line aliases we can now use the clipboard with almost any Linux tool. In the next section, we'll explore some more interesting usages.

Using the Aliases

Most often we'll use the aliases when piping to and from other commands. A pipe is created by separating two commands with a pipe symbol (|). The pipe passes output from the first command to the input of the next.

Piping the output from a command to pbcopy copies it to the clipboard. For instance, to get the current UNIX time, create a pipe from date to pbcopy:

date +%s | pbcopy
Enter fullscreen mode Exit fullscreen mode

On the other hand, piping the output of pbpaste to another command will use the clipboard contents as its input. A Gist can easily be created from the clipboard contents by piping from pbpaste to the awesome gh GitHub CLI tool:

pbpaste | gh gist create -d "Gist created with pbpaste" -f "gist-filename.txt" -
Enter fullscreen mode Exit fullscreen mode

In addition to pipes, redirects make copying and pasting files effortless. By appending > and a file path to a command, its output is redirected to that file. This way, redirecting the output of pbpaste creates a file from the clipboard:

pbpaste > index.js
Enter fullscreen mode Exit fullscreen mode

Be aware output redirects overwrite existing files. To append the output to the end of a file, use >> instead. This can for instance be used to add lines to the Bash configuration file:

pbpaste >> ~/.bashrc
Enter fullscreen mode Exit fullscreen mode

Lastly, the contents of a file can be redirected to the input of a command with <. This lets you copy entire files with pbcopy, for instance, your public SSH key:

pbcopy < ~/.ssh/id_rsa.pub
Enter fullscreen mode Exit fullscreen mode

Avoiding Pitfalls of Copy and Paste

In the previous sections, we've seen how the aliases make using the clipboard in the terminal more streamlined and enjoyable. But there are still even more benefits. The aliases solve many pitfalls of manual copy and paste in the terminal.

When using the aliases you don't have to:

  • remove extra newlines when copying multiple lines
  • add quotes and escape characters when pasting
  • worry about copying too many or too few characters
  • worry about secrets being visible

Implementing the Aliases

Before wrapping up, let's take a look at how the clipboard aliases are implemented. You might have heard WSL lets you run .exe files inside Linux. This means we should be able to access the clipboard from WSL by using Windows command-line clipboard tools.

Conveniently, the PowerShell shell – which comes pre-installed with Windows – has just what we're looking for. Open Windows PowerShell or Windows Terminal to try out the following PowerShell commands:

Write-Output "Hello PowerShell!" | Set-Clipboard
Get-Clipboard
Enter fullscreen mode Exit fullscreen mode

As you can see, Set-Clipboard and Get-Clipboard give us the functionality we need for implementing pbcopy and pbpaste. However, we still need to find a way to run these commands inside WSL. Starting PowerShell inside WSL is as simple as typing powershell.exe. This will start an interactive shell though, which isn't what we want. Instead, we need a way to immediately run the commands and then exit. The -Command flag lets us do just that. Armed with this knowledge we can run Get-Clipboard again, but this time from Linux:

powershell.exe -Command "Get-Clipboard"
Enter fullscreen mode Exit fullscreen mode

Now that pasting works, let's take a moment to look at copying. This time we have to pipe data to powershell.exe, which is a bit more involved. For this we can use the $input variable which is automatically created for us in PowerShell. Passing it to the -Value parameter of Set-Clipboard will set the clipboard from the data piped into PowerShell:

echo 'Hello WSL!' | powershell.exe -Command "Set-Clipboard -Value \$input"
Enter fullscreen mode Exit fullscreen mode

Remember to escape the $ with a slash because $input is a variable in PowerShell. If not, Linux would substitute it before running powershell.exe and it would be the wrong value.

We can now finally both copy and paste inside WSL. But since we'd rather not type long and hard-to-remember commands over and over, we'll define aliases in the Linux shell. This is done with the alias command:

alias pbcopy='powershell.exe -Command "Set-Clipboard -Value \$input"'
alias pbpaste='powershell.exe -Command "Get-Clipboard"'
Enter fullscreen mode Exit fullscreen mode

At last, we've arrived back where we began in Getting Started. With the help of PowerShell, WSL, Linux, and just two lines of code, we now have commands for copying and pasting in the Linux shell.

Conclusion

Manually copying and pasting in the terminal is fraught with problems and annoyances. Clipboard command-line tools avoid many of these issues and integrate nicely with other tools. macOS comes with the built-in pbcopy and pbpaste commands, but getting the same functionality when running a Linux shell with WSL isn't as obvious. In this article, we created similar commands for WSL as command-line aliases.

A big advantage of clipboard command-line tools is being able to copy from and paste to other commands using pipes, and to and from files using redirects. Pipes make it trivial to connect clipboard commands to most command-line tools, such as gh for creating Gists from the clipboard, or uuidgen for copying random UUID values.

I hope pbcopy and pbpaste will help improve your everyday terminal workflow, just as they have for me. Either way, hopefully, this article shed some light on how to integrate Windows and Linux tools using the features of WSL, and inspired you to explore more ways to enhance your terminal experience.


Photo by Jo Szczepanska on Unsplash

Top comments (1)

Collapse
 
emmiep profile image
Emmie Päivärinta

Hi again and thanks for reading my first post to dev.to!

While I was working on this article, I found some slight problems with the aliases regarding how Windows and PowerShell deal with newlines. Most of the time, it probably doesn't even matter, but in some instances it may has a big impact, so I didn't want to leave it out. If you're doing something where it's important the pasted string exactly matches the copied data, like when computing a hash, there are some issues you need to be aware of.

First of all, Windows uses a different character sequence for newlines than Linux and other Unix systems. In Windows, a newline is represented by the "carriage return" character followed by "line feed", which is often represented as CRLF, or \r\n in many programming languages, such as Bash shell scripting. Linux on the other hand just uses the "line feed" character, otherwise LF or \n.

When using Get-Clipboard, newlines always seem to be converted to Windows-style newlines, which might be a problem in some cases. One idea is to use the -Join operator in PowerShell to change the characters used when joining the lines together. This would look something like this:

powershell.exe -Command '(Get-Clipboard) -Join "`n"'
Enter fullscreen mode Exit fullscreen mode

Secondly, by default PowerShell always seems to add a newline to the end of the output. The best solution I've come up with is to pipe the output of Get-Clipboard to Write-Host together with the -NoNewLine flag:

powershell.exe -Command "Get-Clipboard | Write-Host -NoNewLine"
Enter fullscreen mode Exit fullscreen mode

However, I'm not sure if this always works exactly as expected, it might strip the ending newline even when the copied string ends with a newline.

You can combine these commands together, but apparently, there is a way to do both with just Write-Host:

powershell.exe -Command 'Write-Host -NoNewLine -Separator "`n" (Get-Clipboard)'
Enter fullscreen mode Exit fullscreen mode

There may still be some issues, for instance when working with binary data, where both the CRLF and LF character sequences could coexist in the same string and have to be preserved. I'm not entirely sure if it's possible to work around this problem, maybe by invoking C# functions for copy and paste instead.

I'd be grateful if somebody with better PowerShell skills than mine (which are pretty lacking) could provide some feedback. And if anybody is interested in an elaboration on the issues, I could do that too. Once I understand the problem better I would like to update the article or write a follow-up.