7

I'm confused by this experiment (in Bash):

$ mkdir 'foo\n'
$ find . -print0 | od -c
0000000   .  \0   .   /   f   o   o   \   n  \0
0000012

As you can see, "find" is correctly delimiting the output with null characters, but it escapes the newline in the directory name as "foo\n" with a backslash "n". Why is it doing this? I told it "-print0" which says "This allows file names that contain newlines ... to be correctly interpreted by programs that process the find output." The escaping should not be necessary, since "\0" is the delimiter, not "\n".

10
  • 14
    You made a directory called literally foo\n, with a backslash in its name. Feb 23, 2019 at 6:36
  • 7
    Soo ... embarrassing .... but learned something from the answers, thank you all. Feb 23, 2019 at 6:50
  • If you did an ls you would have seen that.
    – Bakuriu
    Feb 23, 2019 at 10:32
  • @Bakuriu, no because ls prints exactly what I passed to mkdir, 'foo\n'... Feb 23, 2019 at 10:42
  • There is no Neulinge in your filename, ‚\n‘ is a literal 2 char string
    – eckes
    Feb 23, 2019 at 15:42

2 Answers 2

20

The problem is not in find, but in how you're creating this directory. The single quoted string 'foo\n' is actually a 5-character string, of which the last two are a backslash and a lowercase "n".

Double-quoting it doesn't help either, since double-quoted strings in shell use backslash as an escape character, but don't really interpret any of the C-style backslash sequences.

In a shell such as bash or zsh, etc. (but not dash from Debian/Ubuntu), you can use $'...', which interprets those sequences:

$ mkdir $'foo\n'

(See bash's documentation for this feature, called "ANSI C Quoting").

Another option, that should work in any shell compatible with bourne shell is to insert an actual newline:

$ mkdir 'foo
'

That's an actual Return at the end of the first line, only closing the single quote on the second line.

0
6

Let's make a directory named foo plus a newline:

$ mkdir $'foo\n'

Now, let's use find:

$ find .  -print0 | od -c
0000000   .  \0   .   /   f   o   o  \n  \0
0000011

\n is not escaped.

The issue is that mkdir 'foo\n' is the name is interpreted as foo followed by \ followed by n. We can verify that with:

$ printf '%s' 'foo\n' | od -c
0000000   f   o   o   \   n
0000005
1

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