3

Consider a list of files (e.g. files.txt) similar (but not limited) to

/root/
/root/lib/
/root/lib/dir1/
/root/lib/dir1/file1
/root/lib/dir1/file2
/root/lib/dir2/
...

How can I copy the specified files (not any other content from the folders which are also specified) to a location of my choice (e.g. ~/destination) with a) intact folder structure but b) N folder components (in the example just /root/) stripped from the path?

I already managed to use

cp --parents `cat files.txt` ~/destination

to copy the files with an intact folder structure, however this results in all files ending up in ~/destination/root/... when I'd like to have them in ~/destination/...

Patrick Storz
  • 425
  • 4
  • 14
  • Is it always going to be just `/root/` stripped? – Robert Seaman Apr 25 '17 at 20:51
  • If you mean: "Can it be hardcoded?" then yes. It might be other paths occasionally though and (if possible) I'd like to avoid `cd`ing into `root` so the script where I want to use it in eventually does not have to play around with the working directory. – Patrick Storz Apr 25 '17 at 20:58
  • In this example, if you had `/root/lib/dir1/` would this then copy all of the files within that directory? You also specify `/root/lib/dir1/file1`, however, this should already be due to the previous line. Is that correct? – Robert Seaman Apr 25 '17 at 21:05
  • No, with the command line above only the specified files are copied. Directories are in fact ignored as I do not specify the `-r` (recursive) option. That is what I want (only the files specified in `files.txt`; no other files that are located in any of the directories specified in `files.txt`). – Patrick Storz Apr 25 '17 at 21:20

2 Answers2

1

I think I found a really nice an concise solution by using GNU tar:

tar cf - -T files.txt | tar xf - -C ~/destination --strip-components=1

Note the --strip-components option that allows to remove an arbitrary number of path components from the beginning of the file name.

One minor problem though: It seems tar always "compresses" the whole content of folders mentioned in files.txt (at least I couldn't find an option to ignore folders), but that is most easily solved using grep:

cat files.txt | grep -v '/$' > files2.txt
Patrick Storz
  • 425
  • 4
  • 14
0

This might not be the most graceful solution - but it works:

for file in $(cat files.txt); do
    echo "checking for $file"
    if [[ -f "$file" ]]; then
        file_folder=$(dirname "$file")
        destination_folder=/destination/${file_folder#/root/}
        echo "copying file $file to $destination_folder"
        mkdir -p "$destination_folder"
        cp "$file" "$destination_folder"
    fi
done

I had a look at cp and rsync, but it looks like they would benefit more if you to cd into /root first.

However, if you did cd to the correct directory before hand, you could always run it as a subshell so that you would be returned to your original location once the subshell has finished.

Robert Seaman
  • 2,432
  • 15
  • 18