[comp.unix.questions] AWK/shell quoting

mike@umn-cs.CS.UMN.EDU (Mike Haertel) (01/07/90)

In article <166@omaha1.UUCP> wcc@omaha1.UUCP (William C Carey) writes:
>Any of the luminaries out there know how to get 'awk' (not nawk) to ouput a
>single-quote character ( ascii 0x27 ).  I can't get the 'print' or
>the 'printf' statement to do it with any combination of backslashes,
>double-quotes, or percent characters.

Your problem is that you are embedding the awk program in a quoted
shell string, and the single quotes you are trying to use in the awk
program are interacting with the shell's quoting conventions.

There are 2 solutions:

1.  You can move the awk program to a file, foo.awk, and then merely
say "awk -f foo.awk" in the shell program.  Then an awk program
to print a single quote would look like:

	BEGIN {print "'"}

2.  You can do it by cooperating with shell quoting.  This is hairy,
but will print a single quote:

	awk 'BEGIN {print "'"'"'"}'

Breaking it down we see that the argument to awk consists of three
concatenated shell-quoted strings:

	'BEGIN {print "'  "'"  '"}'
-- 
Mike Haertel <mike@ai.mit.edu>
"Of course, we have to keep in mind that this year's Killer Micro
 is next year's Lawn Sprinkler Controller . . ." -- Eugene Brooks

dce@smsc.sony.com (David Elliott) (01/07/90)

In article <18067@umn-cs.CS.UMN.EDU> mike@umn-cs.cs.umn.edu (Mike Haertel) writes:
>In article <166@omaha1.UUCP> wcc@omaha1.UUCP (William C Carey) writes:
>>Any of the luminaries out there know how to get 'awk' (not nawk) to ouput a
>>single-quote character ( ascii 0x27 ).  I can't get the 'print' or
>>the 'printf' statement to do it with any combination of backslashes,
>>double-quotes, or percent characters.
...
>2.  You can do it by cooperating with shell quoting.  This is hairy,
>but will print a single quote:
>
>	awk 'BEGIN {print "'"'"'"}'

Hopefully, people tend towards this solution.  Some people I have
worked with like to put awk scripts in separate files.  To me, that's
like breaking up your C program into separate binaries and exec'ing
them as needed - it slows down the program and makes it harder to
maintain.

One trick I use is to say

	awk 'BEGIN {
		Sq = "'"'"'";

and then use Sq wherever I need single quotes.  Also, if you have
an awk that handles octal escapes in sprintf, you could use that
to put a single quote into Sq.

-- 
David Elliott
dce@smsc.sony.com | ...!{uunet,mips}!sonyusa!dce
(408)944-4073
"But Pee Wee... I don't wanna be the baby!"

emb978@leah.Albany.Edu (Eric M. Boehm) (01/07/90)

In article <18067@umn-cs.CS.UMN.EDU> mike@umn-cs.cs.umn.edu (Mike Haertel) writes:
>In article <166@omaha1.UUCP> wcc@omaha1.UUCP (William C Carey) writes:
>>Any of the luminaries out there know how to get 'awk' (not nawk) to ouput a
>>single-quote character ( ascii 0x27 ).
>2.  You can do it by cooperating with shell quoting.  This is hairy,
>but will print a single quote:
>
>	awk 'BEGIN {print "'"'"'"}'

This solutions seem to be overly complex. Maybe I'm picking nits but
wouldn't this be easier and simpler?

awk 'BEGIN { print "\'" }'

Why go through all the silliness with " ' "'" ' " when you can just
escape the single quote? Or is there something I am missing?


-- 
Eric M. Boehm
EMB978@leah.Albany.EDU
EMB978@ALBNYVMS.BITNET

karish@forel.stanford.edu (Chuck Karish) (01/07/90)

In article <2367@leah.Albany.Edu> emb978@leah.Albany.EDU.UUCP
(Eric M. Boehm) wrote:
>In article <18067@umn-cs.CS.UMN.EDU> mike@umn-cs.cs.umn.edu
>(Mike Haertel) writes:
>>In article <166@omaha1.UUCP> wcc@omaha1.UUCP (William C Carey) writes:
>>>Any of the luminaries out there know how to get 'awk' (not nawk) to ouput a
>>>single-quote character ( ascii 0x27 ).
>>2.  You can do it by cooperating with shell quoting.  This is hairy,
>>but will print a single quote:
>>
>>	awk 'BEGIN {print "'"'"'"}'
>
>This solutions seem to be overly complex. Maybe I'm picking nits but
>wouldn't this be easier and simpler?
>
>awk 'BEGIN { print "\'" }'

Have you tried it?

    % awk 'BEGIN { print "\'" }'
    Unmatched ".
    % sh
    $ awk 'BEGIN { print "\'" }'
    > 
    > '
    > "
    awk: newline in string  }'... at source line 1
     context is
            BEGIN { print "\ }' >>> 
     <<< 
    awk: syntax error at source line 3
    awk: illegal statement at source line 3
            missing }


Here's what those nested quotes do:

    awk 'BEGIN {print "'"'"'"}'
                      1234321

    1) Usual quotes to set off a constant string for the 'print' directive
    2) Match the single quotes that set off the whole awk script; text
       within is interpreted by the shell.
    3) Quotes to protect the data from interpretation by the shell.
    4) The data, to be printed unchanged.

	Chuck Karish		karish@mindcraft.com
	(415) 323-9000		karish@forel.stanford.edu

allbery@NCoast.ORG (Brandon S. Allbery) (01/08/90)

As quoted from <1990Jan6.233340.9978@smsc.sony.com> by dce@smsc.sony.com (David Elliott):
+---------------
| In article <18067@umn-cs.CS.UMN.EDU> mike@umn-cs.cs.umn.edu (Mike Haertel) writes:
| >In article <166@omaha1.UUCP> wcc@omaha1.UUCP (William C Carey) writes:
| >>Any of the luminaries out there know how to get 'awk' (not nawk) to ouput a
| >>single-quote character ( ascii 0x27 ).  I can't get the 'print' or
| 
| >2.  You can do it by cooperating with shell quoting.  This is hairy,
| >but will print a single quote:
| >
| >	awk 'BEGIN {print "'"'"'"}'
| 
| One trick I use is to say
| 
| 	awk 'BEGIN {
| 		Sq = "'"'"'";
+---------------

A variant on the above which doesn't require tricky quoting is:

	awk 'BEGIN {
		Sq = sprintf("%c", 39);

++Brandon
-- 
Brandon S. Allbery    allbery@NCoast.ORG, BALLBERY (MCI Mail), ALLBERY (Delphi)
      uunet!cwjcc.cwru.edu!ncoast!allbery ncoast!allbery@cwjcc.cwru.edu
*(comp.sources.misc mail to comp-sources-misc[-request]@backbone.site, please)*
*Third party vote-collection service: send mail to allbery@uunet.uu.net (ONLY)*

allbery@NCoast.ORG (Brandon S. Allbery) (01/08/90)

Someone suggested using \' instead of '.  That won't work; single quoting
takes precedence over backslash escapes, so \ is *ignored* by the shell in
single quotes.  (This is arguably incorrect; were I designing it, I would
choose the escape with the shortest "active time" (e.g. \) as the highest
priority quote, in keeping with the KISS principle.  But it's *far* too late
to change it now.)

++Brandon
-- 
Brandon S. Allbery    allbery@NCoast.ORG, BALLBERY (MCI Mail), ALLBERY (Delphi)
      uunet!cwjcc.cwru.edu!ncoast!allbery ncoast!allbery@cwjcc.cwru.edu
*(comp.sources.misc mail to comp-sources-misc[-request]@backbone.site, please)*
*Third party vote-collection service: send mail to allbery@uunet.uu.net (ONLY)*

emb978@leah.Albany.Edu (Eric M. Boehm) (01/08/90)

In article <6954@lindy.Stanford.EDU> karish@forel.stanford.edu (Chuck Karish) writes:
>>awk 'BEGIN { print "\'" }'
>
>Have you tried it?
>
>    % awk 'BEGIN { print "\'" }'
>    Unmatched ".

Yes, I did try it. However, I did forget that the rules for the c shell
are not those for the Bourne shell. Several people pointed this out to
me. I do check out things before I post but in this case I slipped up. I
will make a point to check both shells in the future.

-- 
Eric M. Boehm
EMB978@leah.Albany.EDU
EMB978@ALBNYVMS.BITNET

lew@gsg.UUCP (Paul Lew) (01/08/90)

>In article <166@omaha1.UUCP> wcc@omaha1.UUCP (William C Carey) writes:
>Any of the luminaries out there know how to get 'awk' (not nawk) to ouput a
>single-quote character ( ascii 0x27 ).  I can't get the 'print' or
>the 'printf' statement to do it with any combination of backslashes,
>double-quotes, or percent characters.

Try avoid using quotes, double-quotes will make life a lot easier.  I use
the following:

	BEGIN	{ q = 39; }
		{
		printf "this is a quote: %c\n", q;
		}

this free you up to worry about what you want to do instead of quoting
problem.  Just remember the decimal value for quote is 39, I did not start
using this method until I memorized its value (the most intuitive reaction
a programmer has at that point is to use "quote" mostly because he can
not remember the decimal value for quote and dont feel like look into the
ASCII table for it!)
-- 
Paul Lew (lew@gsg.gsg.com)		UUCP:		oliveb---+
						uunet---samsung--+
General Systems Group, 5 Manor Parkway			harvard--+--gsg--lew
Salem, NH 03079	(603) 893-1000				decvax---+

brnstnd@stealth.acf.nyu.edu (01/08/90)

(Steve, perhaps my quote and makealias aliases should be in the FAQ list?)

The problem is to feed awk the program
	BEGIN {print "'"}
from csh. Those not yet sufficiently experienced to simply write down a
solution can use my quote alias:
	% quote
	BEGIN {print "'"}     (you type this)
	^D
	'BEGIN {print "'\''"}'
So
	% awk 'BEGIN {print "'\''"}'
works.

And the aliases, in one of my login files:
	a quote "/bin/sed 's/\\!/\\\\\!/g' |
	 	 /bin/sed 's/'\\\''/'\\\'\\\\\\\'\\\''/g' |
	  	 /bin/sed 's/^/'\''/' |
	  	 /bin/sed 's/"\$"/'\''/'"
	a makealias "quote | /bin/sed 's/^/alias \!:1 /' \!:2*"
a is aliased to alias. The quote alias should be all on one line. (On
most machines, you can replace the multiple sed by a single sed with
multiple -e's; unfortunately, this isn't as portable.) quote converts
its input into a csh-compatible quoted output. If you've just typed an
amazing command and want to save it as an alias ``foo'', type
	% makealias foo > addto.login
	(retype the command here and type ^D)
If addto.login looks okay, add it to .login. Or use >>.login directly.

---Dan

brnstnd@stealth.acf.nyu.edu (01/08/90)

In article <2367@leah.Albany.Edu> emb978@leah.Albany.EDU.UUCP (Eric M. Boehm) writes:
> awk 'BEGIN { print "\'" }'

The shell will parse that line into the following chunks:

  awk 'BEGIN { print "\'" }'
  ^^^                   ^^^^ and we're missing a " here.
      ^^^^^^^^^^^^^^^^^^ this is all single-quoted

The backslash doesn't affect the quote because nothing inside single
quotes is interpreted (except history references). 'he\'s' is parsed as
the string he\, followed by s, followed by an unmatched single quote.
Instead of \' you want to escape from single quoting: '\''.

---Dan

brnstnd@stealth.acf.nyu.edu (01/08/90)

In article <6954@lindy.Stanford.EDU> karish@forel.stanford.edu (Chuck Karish) writes:
>     awk 'BEGIN {print "'"'"'"}'
>                       1234321

That numbering may confuse some readers. How about this:

      awk 'BEGIN {print "'"'"'"}'
	  1--------------1   2--2
			  3-3
			4  -  4
			   5

The shell leaves single-quoted text (1-1,2-2) alone. It does a bit of
interpretation (none in this case) on the double-quoted text (3-3).
Awk sees a double-quoted string (4-4) and prints it. The string, of
course, is the completely uninterpreted single quote (5).

I would replace the "'" (3-3) by \', which is a few microseconds faster
and might save a bit of disk space and typing time. :-)

---Dan

hamlin@blackbird.afit.af.mil (Joe Hamlin) (01/08/90)

mike@umn-cs.CS.UMN.EDU (Mike Haertel) writes:

>In article <166@omaha1.UUCP> wcc@omaha1.UUCP (William C Carey) writes:
>>Any of the luminaries out there know how to get 'awk' (not nawk) to ouput a
>>single-quote character ( ascii 0x27 ).  I can't get the 'print' or
>>the 'printf' statement to do it with any combination of backslashes,
>>double-quotes, or percent characters.

>1.  You can move the awk program to a file, foo.awk, and then merely
>say "awk -f foo.awk" in the shell program.  Then an awk program
>	BEGIN {print "'"}

>2.  You can do it by cooperating with shell quoting.  This is hairy,
>	awk 'BEGIN {print "'"'"'"}'

Here's a couple more:

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

or if you need to output the quote in several places, you might
want to try:

awk 'BEGIN {Q = sprintf("%c",39)} {print Q "Don" Q "t quote me on this." Q}'
-- 
Joe Hamlin    <hamlin@blackbird.afit.af.mil>

ijk@cbnewsh.ATT.COM (ihor.j.kinal) (01/11/90)

Why not this:

	awk "BEGIN { print \"'\" } "
	
Yes, I've tried it, and it does work [and it's simpler than the other
suggestions].

<standard disclaimer>
Ihor Kinal
att!cbnewsh!ijk

maart@cs.vu.nl (Maarten Litmaath) (01/11/90)

In article <2368@leah.Albany.Edu> emb978@leah.Albany.Edu (Eric M. Boehm) writes:
\In article <6954@lindy.Stanford.EDU> karish@forel.stanford.edu (Chuck Karish) writes:
\>>awk 'BEGIN { print "\'" }'
\>
\>Have you tried it?
\...
\Yes, I did try it. However, I did forget that the rules for the c shell
\are not those for the Bourne shell. [...]

You didn't check the abovementioned example in the Bourne shell either.
-- 
1755 EST, Dec 14, 1992: Henry Spencer is put on a one-way mission to the moon.|
  Maarten Litmaath @ VU Amsterdam:  maart@cs.vu.nl,  uunet!mcsun!botter!maart

tale@cs.rpi.edu (David C Lawrence) (01/11/90)

In article <7277@cbnewsh.ATT.COM> ijk@cbnewsh.ATT.COM (ihor.j.kinal) writes:
> Why not this:
>          awk "BEGIN { print \"'\" } "
>
> Yes, I've tried it, and it does work [and it's simpler than the other
> suggestions].

For this particular case it is just fine but for most awk expressions,
probably including the one from which this particular question was
derived, you want to put the programme specification in single quotes
and not double quotes so that $ environment variable interpretation is
not done.

Dave
-- 
   (setq mail '("tale@cs.rpi.edu" "tale@ai.mit.edu" "tale@rpitsmts.bitnet"))

brnstnd@stealth.acf.nyu.edu (01/11/90)

In article <7277@cbnewsh.ATT.COM> ijk@cbnewsh.ATT.COM (ihor.j.kinal) writes:
> 	awk "BEGIN { print \"'\" } "

Congratulations for testing your solution before posting it, but it
only works under sh. In contrast,

	awk 'BEGIN { print "'\''" } '

works under sh and csh. (More complicated? Give me a break.)

---Dan

peter@ficc.uu.net (Peter da Silva) (01/12/90)

I don't know about you guys, but if I have an awk script that's giving me
problems I sidestep globbing altogether:

cat >/tmp/awk.$$ << 'EOF'
big, hairy, awk script.
EOF
awk -f /tmp/awk.$$ stuff
rm -f /tmp/awk.$$

This also allows me to gen up parts of the script on the fly a lot easier.
-- 
 _--_|\  Peter da Silva. +1 713 274 5180. <peter@ficc.uu.net>.
/      \
\_.--._/ Xenix Support -- it's not just a job, it's an adventure!
      v  "Have you hugged your wolf today?" `-_-'