Differences between revisions 11 and 12
Revision 11 as of 2009-03-06 09:42:50
Size: 1360
Editor: pgas
Comment: add the pax solution
Revision 12 as of 2009-03-06 14:12:47
Size: 2138
Editor: GreyCat
Comment: clean up
Deletions are marked like this. Additions are marked like this.
Line 3: Line 3:

With GNU `find`(1), the following is likely to be the simplest solution. The second find statement recreates the regular files using "dummy" files (empty files with the same timestamps). (Feel free to replace the `\;` by `+` if your find supports it to reduce the number of `mkdir`/`touch` forks, and thus increase the performance of the command).

{{{
 cd "$srcdir"
 find . -type d -exec mkdir -p "$destination"/{} \;
 find . -type f -exec touch -r {} "$destination"/{} \;
}}}

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

With the {{{cpio}}} program:
With the `cpio` program:
Line 21: Line 10:
or with GNU {{{tar}}}, and more verbose syntax: or with the `pax` program:

{{{
 find . -type d -print | pax -rwv "$dstdir"
}}}

or with GNU `tar`, and more verbose syntax:
Line 29: Line 24:
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. 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`.)
Line 31: Line 26:
or with the {{{pax}}} program: All three of the solutions above will fail if directory names contain newline characters. On many modern BSD/GNU systems, at least the first two can be trivially modified to cope with that, by using `find -print0` and either `pax -0` or `cpio -0`.

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):
Line 34: Line 31:
find . -type d -print | pax -rwv "$dstdir"  cd "$srcdir"
 # insert pax/cpio command here, to make the directories
 find . -type f -exec touch -r {} "$destination"/{} \;
Line 36: Line 35:

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' _ {} +
}}}

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

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

With the cpio program:

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

or with the pax program:

 find . -type d -print | pax -rwv  "$dstdir"

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 three of the solutions above will fail if directory names contain newline characters. On many modern BSD/GNU systems, at least the first two can be trivially modified to cope with that, by using find -print0 and either pax -0 or cpio -0.

If you want to create stub files instead of full-sized files, with GNU 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):

 cd "$srcdir"
 # insert pax/cpio command here, to make the directories
 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' _ {} +

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

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