8

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".

Kusalananda
  • 333,661
Metamorphic
  • 1,179
  • 14
    You made a directory called literally foo\n, with a backslash in its name. – Michael Homer Feb 23 '19 at 06:36
  • 7
    Soo ... embarrassing .... but learned something from the answers, thank you all. – Metamorphic Feb 23 '19 at 06:50
  • If you did an ls you would have seen that. – Bakuriu Feb 23 '19 at 10:32
  • @Bakuriu, no because ls prints exactly what I passed to mkdir, 'foo\n'... – Metamorphic Feb 23 '19 at 10:42
  • There is no Neulinge in your filename, ‚\n‘ is a literal 2 char string – eckes Feb 23 '19 at 15:42
  • @Metamorphic That's exactly my point. If there was a real newline it would print 'foo'$'\n' (at least my /bin/sh – Bakuriu Feb 23 '19 at 20:37
  • @Bakuriu, your reasoning is circular. You said that ls would have helped me. But if I had known that '\n' did not signify a newline, then I would have seen this at the mkdir command. ls did not show me anything I hadn't already seen. What would you think I learned from running ls? I'm not saying I'm not dumb, just maybe a little more awake than you right now :) And why do people keep upvoting this question? It's my worst question! – Metamorphic Feb 23 '19 at 21:27
  • @Metamorphic It's in HNQ is why, and it's there because the review queue hasn't gotten around to closing the question yet since it's the weekend. They will probably keep trickling in for a few more hours at least. – Michael Homer Feb 23 '19 at 23:42
  • I'd vote to close this a duplicate of some question explaining the difference between the different kinds of quotes, but a) I can't find one(?!), and b) there's already three close votes for other reasons than a dup so it wouldn't catch anyway. – ilkkachu Feb 24 '19 at 21:21
  • @ilkkachu I couldn't find one either, so I wrote one - better answers welcome. – Michael Homer Feb 25 '19 at 22:58

2 Answers2

21

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.

filbranden
  • 21,751
  • 4
  • 63
  • 86
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
John1024
  • 74,655