2

I have not been able to find a solution to this seemingly simple problem here or anywhere else. I want to get the paths of all files in a nested directory, add quotes around them, and loop through them in a bash script. Directory names and files can have white spaces in them. So far nothing I tried works properly. The quoted path strings always get broken up at the spaces.

test.sh

for var in "$@"
do
    echo "$var"
done

I tried reading from a file with one path per line, both single and double quotes:

find "nested directory with spaces" -type f | sed -e 's/^/"/g' -e 's/$/"/g' | tr '\n' '\n' > list.txt # double quotes
./test.sh `cat list.txt`

find "nested directory with spaces" -type f | sed -e 's/^/'\''/g' -e 's/$/'\''/g' | tr '\n' ' ' > list.txt # single quotes
./test.sh `cat list.txt`

and command substitution with a space between quoted paths, single and double quotes:

./test.sh `find "nested directory with spaces" -type f | sed -e 's/^/"/g' -e 's/$/"/g' | tr '\n' ' '` # double quotes

./test.sh `find "nested directory with spaces" -type f | sed -e 's/^/'\''/g' -e 's/$/'\''/g' | tr '\n' ' '` # single quotes

Simply echoing a quoted path from the command line gives the desired result. What is missing in the script that can resolve the arguments into complete strings?

1 Answer 1

4

Do it like this instead:

find "nested directory with spaces" -type f -exec ./test.sh {} +

This will call test.sh with multiple arguments, without splitting the spaces in the filenames.

If your version of find doesn't support +, then you can use \; instead, but that will call ./test.sh once for each argument.

For example, given the script:

#!/bin/sh
echo start
for i; do
    echo file: "$i"
done

The difference between + and \;:

$ find a\ b.txt date.txt -exec ./test.sh {} +
start
file: a b.txt
file: date.txt
$ find a\ b.txt date.txt -exec ./test.sh {} \;
start
file: a b.txt
start
file: date.txt
Sign up to request clarification or add additional context in comments.

9 Comments

Wow, that was fast. find "nested directory with spaces" -type f -exec ./test.sh + gives find: -exec: no terminating ";" or "+". find "nested directory with spaces" -type f -exec ./test.sh \; or find "nested directory with spaces" -type f -exec ./test.sh ";" is slow with no output. Same result with my or your version of test.sh. Man page says -exec utility [argument ...] ; … The expression must be terminated by a semicolon (``;''). If you invoke find from a shell you may need to quote the semicolon if the shell would otherwise treat it as a control operator.
I have had problems with the -exec primary. I am using GNU bash, version 4.2.45(2)-release (i386-apple-darwin12.5.0) on OS X 10.8.5 and it is definitely not the standard bash so that may be part of the problem.
@hmj6jmh my bad! At the top of my post I forgot to write {} in there. I wrote it in the examples after that but it's easy to overlook. Btw, based on your error message it looks like your find does support the +, so it will work.
find "nested directory with spaces" -type f -exec ./test.sh {} + worked! Thank you! One more question. This script lists non-existent paths like nested directory with spaces/..files/*. I think this is the result of previous failures when I tried to copy files to nested directory with spaces/..files/. I deleted the directory but it seems the shell still acknowledges it. How do I clear the shell?
@hmj6jmh I don't understand your question.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.