0

I'm trying to run a program on every file on a dir. But there is spaces in the name of the file. For example, a file can be named «/my/good/path/MY - AWFUL, FILE.DOC» And when I'm trying to send the path to my the other tool (a python script), I've got an error saying «MY» is not a existing file. :(

Here is my current bash code:

#!/usr/bin/bash

for file in $(find "/my/pash" -name "*.DOC")
do
    newvar=`program "$file"`
done

So… where is my problem?

Thanks everyone :)

chindit
  • 919
  • 2
  • 9
  • 19
  • Are all of the documents in the same directory, or are they in subdirectories too? – Tom Fenech Apr 04 '15 at 17:48
  • They are in subdirectories. Like «my/path/sub1/MY FILE WITH - SPACES, AND, COMMAS.DOC» – chindit Apr 04 '15 at 17:51
  • Would it be sufficient to do `find '/my/path' -name '*.DOC' -exec script.py {} \;`? – Tom Fenech Apr 04 '15 at 17:53
  • How many questions are there that this is a duplicate of? – Jonathan Leffler Apr 04 '15 at 18:09
  • What do you do with the string captured in `newvar`? Must you process one file at a time, or can `program` process multiple files in a single invocation? If you don't need the output and `program` only handles single files, then @TomFenech's suggestion is good. If `program` handles multiple files, then use `find "/my/pash" -name "*.DOC" -exec program {} +` with a `+` in place of the `\;` behaves more or less like `xargs`, running the program with convenient numbers of files. – Jonathan Leffler Apr 04 '15 at 18:17
  • Please consider using the `$(command)` vs `\`command\`` form of [command substitution](http://www.gnu.org/software/bash/manual/html_node/Command-Substitution.html) – dawg Apr 04 '15 at 18:31

5 Answers5

2

Some correct answers, but no explanations so far:

a for loop is intended to iterate over words not lines. The given (unquoted) string is subject to word splitting (which is what is troubling you) and filename expansion, and then you iterate over the resulting words. You could set IFS to contain only a newline. The safest way is to use find -print0 and xargs -0 as demonstrated by Vytenis's answer

Community
  • 1
  • 1
glenn jackman
  • 238,783
  • 38
  • 220
  • 352
1
#!/usr/bin/bash

find "/my/pash" -name "*.DOC" | while read file; do
  newvar="$(program "$file")"
done

Note that this only fixes the case where a space or tab is in the file name. If you have a newline in the file name, it gets a little more complicated.

Community
  • 1
  • 1
Tim Pote
  • 27,191
  • 6
  • 63
  • 65
1
find -name "*.DOC" -print0 | xargs -r -0 -n1 program
Vytenis Bivainis
  • 2,308
  • 21
  • 28
1

That is because the for loop will take every word inside the result of the find as an element to iterate over. for will see it as:

for file in {/my/good/path/MY, -, AWFUL, FILE.DOC}
    echo "$file"
done

And will print:

/my/good/path/MY
-
AWFUL,
FILE.DOC

One solution to this problem is to use the xargs program to pass the result of the find as your python program argument:

find "/my/pash" -name "*.DOC" -print0 | xargs -0 -i program "{}"
higuaro
  • 15,730
  • 4
  • 36
  • 43
0

the loop treats blanks as delimiter, so try this one:

find "/my/pash" -name "*.DOC" | while read file; do 
   newvar=`program "$file"`
done
leu
  • 2,051
  • 2
  • 12
  • 25