Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

Assuming $file holding a value of a file name, say Dr' A.tif. In bash programming, how could I escape single quote and any other special character of the $file without removing the special character?

Update on 9 July 2014

As request from @Gilles, following code snippet that doesn't able to handle Dr' A.tif:

files=$(find /path/ -maxdepth 1 -name "*.[Pp][Dd][Ff]" -o -name "*.[Tt][Ii][Ff]")
echo "${files}" > ${TEMP_FILE}
while read file
   newfile=$(echo "${file}" | sed 's, ,\\ ,g') ## line 1
done < ${TEMP_FILE}

After I have tried out the answer from @Patrick on line 1, it seems to work for me. But if I have file such as Dr\^s A.tif, printf command doesn't seem help, it shows me Dr\^s\ A.tif. If I manually try it on console like this:

printf "%q" "Dr\^s A.tif"

I will have this output:

Dr\\\^s\ A.tif

Any idea how to handle this?

share|improve this question
in what context are you expecting to use $file? or is this issue assigning the string with the special character to $file? – rob Jul 8 '14 at 10:50
Actually the find command return me an array of file list. And then I loop through this file list into $file variable. – huahsin68 Jul 8 '14 at 10:56
You've been given some correct answers here, but they are probably not the answers to the question that you're really asking. From your comment here, I strongly suspect that you're on the wrong track. We can't help you much because you keep not showing your code. I do however recommend that you read Why does my shell script choke on whitespace or other special characters? as background. Show your script and explain what you want to do. – Gilles Jul 8 '14 at 21:18

You can use the printf builtin with %q to accomplish this. For example:

# file="Dr' A.tif"
# printf '%q\n' "$file"
Dr\'\ A.tif

# file=' foo$bar\baz`'
# printf '%q\n' "$file"
\ foo\$bar\\baz\`


From the bash documentation on printf:

In addition to the standard format specifications described in printf(1)
and printf(3), printf interprets:

 %b       expand backslash escape sequences in the corresponding argument
 %q       quote the argument in a way that can be reused as shell input
 %(fmt)T  output the date-time string resulting from using FMT as a format
          string for strftime(3)
share|improve this answer
This doesn't work with certain cases .e.g. when you need to preserve double-quotes. – user3467349 Nov 7 '15 at 6:08
@user3467349 it works just fine with quotes. I'm betting you're trying something like printf '%s' "foo". You need to understand how argument parsing works in the shell first. See gnu.org/software/bash/manual/bash.html#Shell-Operation #2 happens before #6. – Patrick Nov 7 '15 at 18:49
Could you provide an example of this string printed with printf and no other manipulations It doesn't have a: "" – user3467349 Nov 8 '15 at 4:25
Your issue has nothing to do with printf. Your issue is that you don't want the shell to parse your string. In order to do that, you have to pass your input to the shell in a way where it doesn't even try to parse it. One way to do this would be read -r -p 'input: ' && printf '%q\n' "$REPLY", and provide the input when prompted. – Patrick Nov 8 '15 at 6:48
Provide input while prompted won't work well in a shell script, neither is it speedy even interactively. Hence my above comment about this being a limited / sub-optimal solution. – user3467349 Nov 8 '15 at 10:10


file=Dr\'\ A.tif
echo $file
Dr' A.tif


file="Dr' A.tif"
echo $file
Dr' A.tif

or if the string contains a double quote:-

file='Dr" A.tif'
echo $file
Dr" A.tif

There are good tutorials on escaping and quoting on the net. Start with this one.

share|improve this answer

You don't need to escape any file names you are handling in a script. Escaping is only necessary if you want to put a file name as a literal in a script, or to pass several file names as a single input stream to another script.

Since you're looping through the output of find, this is one of the simplest ways (!) to handle every possible path:

while IFS= read -r -d ''
    file_namex="$(basename -- "$REPLY"; echo x)"
    do_something -- "$file_name"
done <(find "$some_path" -exec printf '%s\0' {} +)
share|improve this answer

A lot of these answers including the top-voted one using printf "%q" will not work in all cases without additional manipulation. I would suggest the following (example below):

cat <<EOF; 2015-11-07T03:34:41Z app[postgres.0000]: [TAG] text-search query doesn't contain lexemes: "" EOF

share|improve this answer

quick and (very) dirty

find . | sed 's/^/"/' | sed 's/$/"/'
share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

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