Shells, quoting, and one-liners

The goal this post is to show how to call Perl and Python one-liners from a shell. We want to be able to use bash on Linux, and cmd or PowerShell on Windows, ideally with the same code in all three shells.

Bash

Bash interprets text inside double quotes but not in single quotes. So if you want to send a string to a program unmolested, you surround it with single quotes.

For example, suppose I want to write a Perl one-line program to print hello. This works:

    perl -e 'print "hello\n"'

The single quotes tell the shell to pass what’s inside to perl without doing anything to it.

The corresponding Python example would be

    python -c 'print("hello\n")'

and this also works.

Cmd and PowerShell

For reasons I don’t understand, the Perl example above works from cmd, but the Python example does not.

And neither example works in PowerShell. This is particularly puzzling since PowerShell follows basically the same quoting rules as bash: double quotes interpolate but single quotes do not.

Workarounds

There are ways to fix the problems with cmd and PowerShell without breaking bash.

Perl

Perl has a handy feature for avoiding confusion over quotes: you can use q{} for single quotes and qq{} for double quotes. If I write the Perl example as

    perl -e 'print qq{hello\n}'

then it works everywhere: bash, cmd, and PowerShell.

Python

Python makes no distinction between single and double quotes, so you can reverse the role of single and double quotes to avoid quoting confusion. The code

    python -c "print('hello\n')"

works everywhere.

Printing quote marks

In the previous section we said we can get around problems in Perl by using q{} and qq{}, and get around problems in Python by switching to double quotes on the outside and single quotes on the inside. But what if we wanted to print a single or double quote mark, such as printing 'hello' or "hello"?

You can escape single quotes with \' and double quotes with \", but you run into things that work on cmd but not on bash, or work on bash but not in PowerShell, etc.

One sure-fire way to make quotes work, in Perl and in Python, and on every shell we’re considering, is to denote quotes by their Unicode values, i.e. to use \x27 for single quotes and \x22 for double quotes. The one-liners

    perl -e 'print qq{\x27hello\x27\n}'

and

    python -c "print('\x27hello\x27\n')"

print 'hello' in bash, cmd, and PowerShell.

And similarly

    perl -e 'print qq{\x22hello\x22\n}'

and

    python -c "print('\x22hello\x22\n')"

print "hello" in bash, cmd, and PowerShell.

Guidelines for portable one-liners

In summary, you can avoid problems with Perl one-liners by using q{} and qq{} inside code rather than single or double quotes. For Python one-liners, you can swap single quotes and double quotes.

On Linux (bash) surround code with single quotes. On Windows (cmd and PowerShell) surround code with double quotes.

Use character codes for literal quote characters. This isn’t necessary, but if you do this you won’t have to remember how quotes and escapes work on different platforms.

Further reading

5 thoughts on “Shells, quoting, and one-liners

  1. Severin Pappadeux

    Mmm… I’m using powershell 7.x (.0 and .1 as well, in Windows 10 x64) running in Windows Terminal. Python is pretty standard, x64 v3.8.6 from Python dot org. Tried again – works for me

  2. Severin Pappadeux

    And powershell 5.1 (came with Win 10, I believe) in Windows terminal works well.

    Looks like copy/paste from browser to terminal mangle something (first apostrophe looks a bit suspicious)

  3. Something strange is going on. I pasted the line in question and it didn’t work. Then I copied it from the shell, pasted it in again, and the second time it ran.

    So apparently, something change when copying from the browser to the shell that broke the code, but copying from the shell to itself also changed the code, but in a way that fixed the code!

Comments are closed.