Bash/C shell: Are there any drawbacks about escaping all characters of a file path?
The example you've given won't work because in general a single character preceded by a backslash does not escape the character, but introduces a new meaning. \n
for example is not n
escaped, but the newline character.
Another way of escaping special characters is to enclose everything in quotes, e.g.
"/my/path/to/file.txt"
With this you only need to escape the quote character "
, i.e. \"
. Alternatively, you can use a single quote character around the path, e.g.
'/my/path/to/file.txt'
Same applies here, if the path contains a '
, you need to escape it.
What you care about in a program like this are two things:
- Functionality
- Readability
The first point is obvious - You need the correct string to be passed from one program to the other. In Bash there are only two ways you can write absolutely any filename in a script. Given for example a filename like this:
$ echo -n $'\a\b\E\f\r\t\v\'"\360\240\202\211 \n' | uniname -pcbUTF-32 encoded as glyph name000007 07 BELL000008 08 BACKSPACE00001B 1B ESCAPE00000C 0C FORM FEED (FF)00000D 0D CARRIAGE RETURN (CR)000009 09 CHARACTER TABULATION00000B 0B LINE TABULATION000027 27 ' APOSTROPHE000022 22 " QUOTATION MARK020089 F0 A0 82 89 𠂉 Unknown character in range CJK Unified Ideographs Extension B000020 20 SPACE00000A 0A LINE FEED (LF)
There are five ways to write strings in Bash, one of which ($""
) is not relevant for this purpose:
Literal stringwith escape characters. There's no way to include a literal newline this way, so that's out. Example:$ foo=bar$ bazNo command 'baz' found, did you mean: ...$ foo=bar\> baz$ echo "$foo"barbaz$ foo=bar\nbaz$ echo "$foo"barnbaz$ foo=bar\\nbaz$ echo "$foo"bar\nbaz
Single-quoted string. These can't contain other single quotes, so they're out.- Double-quoted string. You can put anything in these, but you have to escape some characters if you want their literal representation - Simply preceding every character with a backslash is not likely to produce the result you want. Also, complicated characters like
BELL
will have to be included as a literal, making it effectively invisible to the person reading the script or output. - ANSI-C Quoting, shown above. This can also contain any character, but you can escape special characters to make the string more readable.
Of the two methods, it's pretty clear that if you want to print any filename you should use ANSI-C Quoting if you don't know what the string might contain. But if you want to always use the "minimal" escaping, you can print the value using printf %q
- Compare:
$ printf %q $'word'word$ printf %q $'space separated'space\ separated$ printf %q $'newline\nembedded'$'newline\nembedded'
Not quite what you asked, but might be the best solution given the added reason: python's pipes
module has a function called quote
, which you can import and which quotes pathnames for shell commands:
$ python...>>> from pipes import quote>>> quote('filename')'filename'>>> quote('filename with "funny"\tcharacters')'\'filename with "funny"\tcharacters\''>>> >>> quote("filename with 'single quotes'")'\'filename with \'"\'"\'single quotes\'"\'"\'\''>>>