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.
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.
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.
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.
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"}'
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.
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.
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"}'
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.
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"}'
awk $'BEGIN{print "it said \'Hello, World!\' and then returned 0";exit 0}'