1. In the "A" directory: find . -type f > a.txt
  2. In the "B" directory: cat a.txt | while read FILENAMES; do touch "$FILENAMES"; done

Result: Step 2 "creates the files" (I mean only with the same filename, but with 0 Byte size) but if there are subdirs in the "A" directory, then step 2 can't create the files in the subdir, because there are no directories in it.

Question: Is there a way, that "touch" can create directories?


quick shot:

while read FILENAME
  mkdir -p $(dirname "$FILENAME") && touch "$FILENAME"
done < a.txt

Be aware of special chars (whitespaces, ...) in file-/pathnames and so on ...

  • 2
    then you also want double-quotes around the $(...) substitution, to protect against whitespace-splitting of the result, and should figure out how to deal with newlines embedded in the filenames. find's -print0 and using a shell which supports having read use a NUL delimiter may help. – Phil P Jan 17 '11 at 9:59
  • Phil P is right, you can put quotes around the $(..), even if it contains quotes itself (as in this case) and Bash will do The Right Thing. – Javier Jan 17 '11 at 12:41

I'm on quite a GNU parallel kick lately. Here's a way to do this in one line using that tool:

find A -type d | parallel 'mkdir -p B/$(dirname {})' && find . -type f | parallel 'touch B/{}'

Note that this is inefficient because it runs a lot of extra unneeded mkdir -p for intermediary directories. That should be optimized if you are dealing with really huge directory structures.


in the original, "A" directory:

find . -type f > a.txt

"B" directory:

while read file; do if [[ "$file" = */* ]]; then mkdir -p "${file%/*}"; fi; touch "$file"; done < a.txt

This works even if A contains the file:

A/My brother's 12" records dir/My brother's 12" records

(cd A; find . -type f) | (cd B; parallel 'mkdir -p {//}; touch {}')

Having dealt with users creating "creative" filenames I always test script like these on

My brother's 12" records

If it works for that, then chances are good it will not fail.

Thanks to Phil H for giving the basic building blocks.


Before doing:

cat a.txt | while read FILENAMES; do touch "$FILENAMES"; done


cat a.txt | sed -e `s|/[^/]*$||` | uniq | while read DIRNAMES; do mkdir -p "$DIRNAMES"; done

As already pointed out, be careful about special char in dirnames/filenames, especially slashes (I would hate to have a file named "aaa/ccc", but it is always possible).

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.