This problem has enough layers of complexity to make simple escaping characters difficult for me. I have a bash script which, for a large part, has an embedded awk script that reads a file delimited by semicolons. In this text file, one of the fields is a directory path to some JPEGs. I'd like to copy the JPEGs somewhere else, but the original directory path has spaces in it (and could potentially have other strings that could do damage). I can't refer to the directory in question with single quotes because this stops the awk interpreter, and double quotes turns it into a literal string in awk.

I'm using gawk 4.1.1. Here's some awk code of what I'm trying to accomplish:

imageDirectory = $1;
cpJpegVariable="cp -r " imageDirectory " assets";
#screws up if imageDirectory has spaces and other naughty characters

You can use:

awk '...
    cpJpegVariable="cp -r '\''" imageDirectory "'\'' assets";

(note that ' doesn't need escaping for awk, but you need '\'' for the shell). So when awk expands variable cpJpegVariable, it looks like:

cp -r 'file_contain space' assets

With that, you can avoid problem with all special characters, except ' itself. If imageDirectory may contain single quote characters, you can escape them with gsub(). Example:

awk '{gsub("'\''","'\''\"'\''\"",imageDirectory)}1'
  • Worked perfectly, and embarassingly obivous in hindsight. Thanks very much. – Escher Aug 5 '14 at 8:34
  • 1
    Note that while it fixes the problem with space, tab, ;, |, & and many other characters, it does not fix it for filenames that contain backtick, backslash, $ or " characters (or whose name starts with -). – Stéphane Chazelas Aug 5 '14 at 8:46
  • @StéphaneChazelas: If change \" to \', problem maybe fixed? – cuonglm Aug 5 '14 at 8:48
  • To ' you mean? Then, the only problematic character becomes ' itself (which you can escape with a gsub command). – Stéphane Chazelas Aug 5 '14 at 9:08
  • @StéphaneChazelas: Thanks for suggestion, fixed! – cuonglm Aug 5 '14 at 9:21

If you are passing an Awk variable to system, you need to shell quote it:

function quote(str,   d, m, x, y, z) {
  d = "\47"; m = split(str, x, d)
  for (y in x) z = z d x[y] d (y < m ? "\\" d : "")
  return z


system(sprintf("cp -r %s assets", quote($1)))



Executing external commands is meant for the shell, not for awk:

while read image_dir __; do
    cp -r "$image_dir" assets
done < file
  • It is sometimes necessary or useful to execute a system command based on information that was read by awk. This is why system() exists. – Escher Aug 5 '14 at 10:30
  • system() is not consistent with all types of input. It's awfully difficult to sanitize it. – konsolebox Aug 5 '14 at 10:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.