4

Is there a way to copy a list of files, that share a common base directory, preserving their relative directory structure? The files with relative paths are listed in a text file. edit I have the filenames listed in a plain text file.

I'd like to do this without using a script (no bash/batch/python/ruby/lua/etc.), similar to how wget -i works for urls. (My reason is that it'd give overhead/non-standard solution for a reasonably common task.)

I've tried cat list.txt | xargs -I % cp % new_folder from Copy list of files but it didn't preserve the relative directory path.

I'd do this to export my selection of files (that I already have in a text file) from a directory structure that has big number of files (happens from time to time).

n611x007
  • 6,566
  • 15
  • 67
  • 91

3 Answers3

6

The answer of unixUser set me on the right track. Turns out that tar can do both reading file and directory names from a text file with -T, and can even change directory with -C:

tar cvf - -T filelist.txt | tar xvf - -C newdir

This answers the question I had.


sources

To obtain this information from the idea unixUser gave me, I've ducked for tar files from text file, leading to trpn's (Q) and Tinkster's (A) conversion on linuxquestions.org. Simultaneously checking the tar manual page for any option that has something to do with file, both search led to the -T switch! To avoid relying on shell for changing directory, I've also searched it for any directory related options and found the -C switch. -- I see that tar is probably the command meant for grouping (copies of) files in many ways.

With this, one can use some tar binary without* relying on scripting. Just amazing how useful tar is.


(*: out of preference: I find bash/perl/python/whatever a too general tool for this quite exact task. However, as pointed out by grawity, pipes are convenient - without them one should be forced to create an intermediate file, eg. tar cvf intermediate.tar -T filelist.txt and tar xvf intermediate.tar -C newdir.)

Pang
  • 1,017
n611x007
  • 6,566
  • 15
  • 67
  • 91
4

tar cvf - ./filesAndDirecotries | (cd targetDirectory ; tar xvf - )

TAR (Tape Archive is old command to create an archive file) can write to stdin ( " - " parameter for the file ) and pipe and read from stdin in the second directory.

Above command first creates a tar file and writes to stdin and piped to a shell and change directory and untar the file by reading it from stdin.

unixUser
  • 64
  • 1
1

Technically, your given example already uses bash. And that's exactly why the shell is scriptable in the first place – it's such a simple task that there is no need for a dedicated tool/program just for it.

cat list.txt | xargs -n1 dirname | sort | uniq | xargs -I% mkdir -p new_folder/%
cat list.txt | xargs -I% cp % new_folder/%

Or:

cat list.txt | while read path; do
    mkdir -p "new_folder/${path%/*}" && cp "$path" "new_folder/$path"
done

Or:

cat list.txt | xargs -I% install -Dm0644 % new_folder/%

Or:

cat list.txt | while read path; do
    install -Dm0644 "$path" "new_folder/$path"
done

(install is shorter but does not preserve modes, unfortunately.)

grawity
  • 501,077