How can find search results containing spaces to be printed with enclosing '' (a quote pair). Only if this result contains spaces, if there are not spaces in the path string, to remain as is.
- 8,122
3 Answers
Here is a way to do it using just find if your version supports -printf.
find . -name "* *" -printf "\"%p\"\n" -o -print
- 136
- 4
-
Note: From Stéphane Chazelas, you may want to set
LC_ALL=Cbefore this command so that the '*' will match bytes that are not valid characters. That is probably not necessary 99.9% of the time, so I think it should be here as a note instead of in the answer. – bdowling Oct 28 '20 at 07:13 -
Edited. Thanks, Stéphane. That is probably what most people would want. – bdowling Oct 29 '20 at 08:23
Assuming you want to generate CSV output, with GNU tools:
find . -print0 |
LC_ALL=C sed -z '/[",[:space:]]/{s/"/""/g; s/.*/"&"/}' |
tr '\0' '\n'
That is, as long as the file name contains at least one ", , or ASCII whitespace character (including, but not limited to SPC, TAB, CR and newline all special in CSV), translate " to "" (which is how most CSV formats escape the "s), and enclose the string in double quotes.
That part is done using NUL as the record delimiter since it's the only byte that can't occur in a file path. And then, we translate NULs to newline with tr.
On non-GNU systems, you can always resort to perl:
find . -print0 | perl -l -0 -pe 'if (/[",\s]/) {s/"/""/g; $_ = "\"$_\""}'
After
touch 'a b' $'a\nb' a,b a_b $'a\200b' 'a"b'
They give:
.
"./a""b"
./a_b
"./a,b"
./a�b
"./a
b"
"./a b"
(where � is my terminal's rendition of that \200 byte that doesn't form a valid character in my UTF-8 locale).
To exclude . and the ./ prefix, replace -print0 with -mindepth 1 -printf '%P\0' (though -printf is GNU-specific). Which gives:
"a""b"
a_b
"a,b"
a�b
"a
b"
"a b"
-print0 and -mindepth are also GNU extensions, but they have since been copied to a few other implementations. If your implementation is one of the few where that still don't have them, you can replace:
find . -print0withfind . -exec printf '%s\0' {} +find . -mindepth 1 -printf '%P\0'withfind . ! -name . -exec sh -c 'for i do printf "%s\0" "${i#./}"; done' sh {} +
- 544,893
You can do it by piping the output to awk:
find . | awk '/ /{ printf"\"%s\"\n", $0; next } { print }'
- 136
- 4
-print0if yourfindimplementation supports it – steeldriver Oct 28 '20 at 01:49-path '* *' -printf '"%p"\n' -o -printI suppose – steeldriver Oct 28 '20 at 04:31-print0you can reliably do something to a file (with any valid name) thanks to-exec. – Kamil Maciorowski Oct 28 '20 at 06:18