How can I escape white space in a bash loop list? How can I escape white space in a bash loop list? bash bash

How can I escape white space in a bash loop list?


First, don't do it that way. The best approach is to use find -exec properly:

# this is safefind test -type d -exec echo '{}' +

The other safe approach is to use NUL-terminated list, though this requires that your find support -print0:

# this is safewhile IFS= read -r -d '' n; do  printf '%q\n' "$n"done < <(find test -mindepth 1 -type d -print0)

You can also populate an array from find, and pass that array later:

# this is safedeclare -a myarraywhile IFS= read -r -d '' n; do  myarray+=( "$n" )done < <(find test -mindepth 1 -type d -print0)printf '%q\n' "${myarray[@]}" # printf is an example; use it however you want

If your find doesn't support -print0, your result is then unsafe -- the below will not behave as desired if files exist containing newlines in their names (which, yes, is legal):

# this is unsafewhile IFS= read -r n; do  printf '%q\n' "$n"done < <(find test -mindepth 1 -type d)

If one isn't going to use one of the above, a third approach (less efficient in terms of both time and memory usage, as it reads the entire output of the subprocess before doing word-splitting) is to use an IFS variable which doesn't contain the space character. Turn off globbing (set -f) to prevent strings containing glob characters such as [], * or ? from being expanded:

# this is unsafe (but less unsafe than it would be without the following precautions)( IFS=$'\n' # split only on newlines set -f    # disable globbing for n in $(find test -mindepth 1 -type d); do   printf '%q\n' "$n" done)

Finally, for the command-line parameter case, you should be using arrays if your shell supports them (i.e. it's ksh, bash or zsh):

# this is safefor d in "$@"; do  printf '%s\n' "$d"done

will maintain separation. Note that the quoting (and the use of $@ rather than $*) is important. Arrays can be populated in other ways as well, such as glob expressions:

# this is safeentries=( test/* )for d in "${entries[@]}"; do  printf '%s\n' "$d"done


find . -type d | while read file; do echo $file; done

However, doesn't work if the file-name contains newlines. The above is the only solution i know of when you actually want to have the directory name in a variable. If you just want to execute some command, use xargs.

find . -type d -print0 | xargs -0 echo 'The directory is: '


Here is a simple solution which handles tabs and/or whitespaces in the filename. If you have to deal with other strange characters in the filename like newlines, pick another answer.

The test directory

ls -F testBaltimore/  Cherry Hill/  Edison/  New York City/  Philadelphia/  cities.txt

The code to go into the directories

find test -type d | while read f ; do  echo "$f"done

The filename must be quoted ("$f") if used as argument. Without quotes, the spaces act as argument separator and multiple arguments are given to the invoked command.

And the output:

test/Baltimoretest/Cherry Hilltest/Edisontest/New York Citytest/Philadelphia