Differences between revisions 19 and 22 (spanning 3 versions)
Revision 19 as of 2013-09-19 16:25:56
Size: 2467
Editor: ogw01
Comment: the '/' glob qualifier will make the glob only match directories and not other types of files.
Revision 22 as of 2013-10-27 23:05:40
Size: 2315
Editor: GreyCat
Comment: remove nonstandard find solution, since there's a better one sitting right there
Deletions are marked like this. Additions are marked like this.
Line 2: Line 2:
Line 9: Line 10:
Line 16: Line 16:
Line 26: Line 25:
Line 34: Line 32:
Line 39: Line 36:
If you want to create stub files instead of full-sized files, with GNU [[UsingFind|find(1)]], the following is likely to be the simplest solution. The `find` command recreates the regular files using "dummy" files (empty files with the same timestamps): If you want to create stub files instead of full-sized files, the following is likely to be the simplest solution. The `find` command recreates the regular files using "dummy" files (empty files with the same timestamps):
Line 43: Line 40:
 # use one of the above commands first, to make the directories, then:
 find . -type f -exec touch -r {} "$destination"/{} \;
}}}

Be aware, though, that according to POSIX, the behaviour of `find` is unspecified when `{}` is not standing alone in an argument. Because of this, the following solution is more portable (and probably faster...) than the previous:

{{{
 dstdir=whatever; export dstdir
 find . -type f -exec sh -c 'for i; do touch -r "$i" "$dstdir"/"$i"; done' _ {} +
 find . -type f -exec sh -c \
   'dstdir=$1; shift; for i; do touch -r "$i" "$dstdir"/"$i"; done' _ "$dstdir" {} +
Line 56: Line 46:
Or use `find` with `xargs`:

{{{
find "$src" -type d | sed "s@^$src@@g" | (cd "$dst" && xargs -n1 mkdir)
}}}

(This solution is not recommended, as it fails if `$src` contains any `@` characters, or any characters that have special meaning to `sed`.)

How can I recreate a directory hierarchy structure, without the files?

With the cpio program:

 cd "$srcdir" &&
 find . -type d -print | cpio -pdumv "$dstdir"

or with the pax program:

 cd "$srcdir" &&
 find . -type d -print | pax -rwdv  "$dstdir"

or with zsh's special globbing:

 zsh -ec '
 cd -- "$srcdir"
 dirs=(**/*(/ND))
 cd -- "$dstdir"
 mkdir -p -- $dirs[@]'

or with GNU tar, and more verbose syntax:

 cd "$srcdir" &&
 find . -type d -print | tar c --files-from - --no-recursion |
   tar x --directory "$dstdir"

This creates a list of directory names with find, non-recursively adds just the directories to an archive, and pipes it to a second tar instance to extract it at the target location. As you can see, tar is the least suited to this task, but people just adore it, so it has to be included here to appease the tar fanboy crowd. (Note: you can't even do this at all with a typical Unix tar. Also note: there is no such thing as "standard tar", as both tar and cpio were intentionally omitted from POSIX in favor of pax.)

All but the zsh solution above will fail if directory names contain newline characters. On many modern BSD/GNU systems, at least, they can be trivially modified to cope with that, by using find -print0 and one of pax -0 or cpio -0 or tar --null (check your system documentation to see which of these commands you have, and which extensions are available).

If you want to create stub files instead of full-sized files, the following is likely to be the simplest solution. The find command recreates the regular files using "dummy" files (empty files with the same timestamps):

 cd "$srcdir" &&
 find . -type f -exec sh -c \
   'dstdir=$1; shift; for i; do touch -r "$i" "$dstdir"/"$i"; done' _ "$dstdir" {} +

If your find can't handle -exec + then you can use \; instead of + at the end of the command. See UsingFind for explanations.

Or use find with xargs:

find "$src" -type d | sed "s@^$src@@g" | (cd "$dst" && xargs -n1 mkdir)

(This solution is not recommended, as it fails if $src contains any @ characters, or any characters that have special meaning to sed.)


CategoryShell

BashFAQ/010 (last edited 2023-09-22 06:29:48 by StephaneChazelas)