Shell:复制具有完整文件夹结构的文件列表,从文件名中剥离 N 个前导组件

Shell: Copy list of files with full folder structure stripping N leading components from file names

考虑类似于(但不限于)

的文件列表(例如 files.txt
/root/
/root/lib/
/root/lib/dir1/
/root/lib/dir1/file1
/root/lib/dir1/file2
/root/lib/dir2/
...

如何使用 a)[=29 将指定的文件(不是指定文件夹中的任何其他内容)复制到我选择的位置(例如 ~/destination) =] 完整的文件夹结构 but b) 从路径中剥离了 N 个文件夹组件(在示例中只是 /root/)?

我已经成功使用了

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

复制具有完整文件夹结构的文件,但是当我想将它们放在 ~/destination/...

中时,这会导致所有文件以 ~/destination/root/... 结尾

这可能不是最优雅的解决方案 - 但它有效:

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

我看过 cprsync,但如果您先 cd 进入 /root,看起来他们会受益更多。

但是,如果您事先 cd 到正确的目录,您总是可以 运行 它作为一个子 shell,以便在子 shell 完成后返回到您的原始位置。

我想我通过使用 GNU tar:

找到了一个非常好的简洁的解决方案
tar cf - -T files.txt | tar xf - -C ~/destination --strip-components=1

请注意 --strip-components 选项,该选项允许从文件名开头删除任意数量的路径组件。

不过有一个小问题:似乎 tar 总是 "compresses" files.txt 中提到的文件夹的全部内容(至少我找不到忽略文件夹的选项),但使用 grep:

最容易解决
cat files.txt | grep -v '/$' > files2.txt