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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.