PrintASingleQuote

This question gets asked often enough that it deserves its own answer. This common question doesn't actually point to a shortcoming of awk: rather, it is almost always due to the way that shell quoting interacts with the singlequote character.

The Short Story

Use octal escape sequences ('\047') or printf ('printf "%c", 39'). Do not use hex escape sequences ('\x27') because they can interact badly with the surrounding text in different ways depending on your awk implementation.

The Rambling Tale

In order to print out the string "it said 'Hello, World!' and then returned 0", one can run the following program:

BEGIN {
	print "it said 'Hello, World!' and then returned 0"
	exit 0
}

However, when one attempts something similar on the command line:

awk 'BEGIN{print "it said 'Hello, World!' and then returned 0";exit 0}'

...the shell complains, because it tries to parse "Hello, World!" as a string of commands to be inserted between two singlequoted strings.

The first thought one might have is to surround the program fragment in double quotes rather than single quotes, but this interacts very badly with awk's literal string syntax and the "$" field reference operator.

Hex Escapes: Bad Juju

Frustratingly, the next most obvious solution - using hex-escaped characters - seems to work at first:

awk 'BEGIN{print "it said \x27Hello, World!\x27 and then returned 0";exit 0}'

...but this consistency is a sham. Try the following fragment instead in gawk, mawk and busybox awk and compare the results:

awk 'BEGIN{print "\x27foo!\x27"}'

Note that mawk and busybox awk print the expected string, but that gawk returns a [[multibyte?]] character. As mentioned in paragraph 3 of the Rationale section of the Open Group Base Specifications issue 6, and as reiterated in the GNU awk manual in section 2.2 ("Escape Sequences"), the '\xHH' hexadecimal notation is ambiguous because it allows more than two successive hex bytes to be specified. Unfortunately the precise behaviour when more than two bytes are given is allowed to be implementation dependent.

Octal Escapes: Great Personality, but...

Fortunately we can always regress to stone knives and bearskins: octal escape sequences are required to have a fixed length.

awk 'BEGIN{print "\047foo!\047"}'

Uses and Abuses of printf

Or we could use printf:

awk 'BEGIN{printf "%cfoo!%c\n", 39, 39}'

...but then we have to start counting to make sure that all the escape sequences have a corresponding number. gawk features a printf extension for re-using printf arguments according to a position specified in the string sequence..:

awk 'BEGIN{printf "%1$cfoo!%1$c\n", 39}'

...but that compromise is far too ugly for polite company, so let's pretend we didn't mention it.

Explicit Concatenation (oh my!)

There is also the old fallback of putting a single quote character in its own variable and then using explicit string concatenation:

awk 'BEGIN{q="\047";print q"foo!"q}'

...but that gets ugly when dealing with a long string that contains many single quote characters.

Being Creative

Other ways include: escaping the single quote in the shell ('\'') and writing the hex character at the end of a string:

awk 'BEGIN{print "it said '\''Hello, World!'\'' and then returned 0"}'
awk 'BEGIN{print "it said \x27""Hello, World!\x27"" and then returned 0"}'

Do The Right Thing

The cleanest way is simply to write the program in its own file. There may also be shell-specific ways for working around the quoting problem: please feel free to add them to this page if you know any.

Feed the quote as a variable to awk

Another way is to provide the quote to awk as a variable:

--single quote

awk -v q="'" 'BEGIN{print "it said " q "Hello, World!" q " and then returned 0"}'

--double quote

awk -v q='"'  'BEGIN{print "it said " q "Hello, World!" q " and then returned 0"}'

Using bash's quoting($'string')

awk $'BEGIN{print "it said \'Hello, World!\' and then returned 0";exit 0}'