tar 使用名称为 space 的 files/folders 输入列表

tar using input list of files/folders with space in their names

目录中有带空格的文件和子文件夹:

$ find ./test
./test
./test/testdir
./test/testdir/file 1 2 3
./test/testdir 2 3 4
./test/testdir 2 3 4/file 5 6 7
./test/testfile
./test/otherdir
./test/otherdir/otherfile
./test/otherfile
$

这只是展示案例的测试文件夹示例,但在真实环境中,这是一个巨大的文件夹,包含数百个文件,总大小约为 . 100GB.

我有一个 zip 文件,其中包含上述文件夹中某些文件的更新。在解压缩更新文件之前,我想对每个将被此更新替换的文件进行选择性备份。

update.zip 文件中的文件是:

    $ unzip -Z1 update.zip
    testdir/
    testdir/file 1 2 3
    testdir 2 3 4/
    testdir 2 3 4/file 5 6 7
    testfile
    $

Here is the command which I tried to do such backup which failed:

$ tar czvf backup_before_update.tgz -C ./test/ $(unzip -Z1 update.zip|grep -v \/$|sed -r 's/^/"/;s/$/"/'|paste -sd" ")
tar: "testdir/file: Cannot stat: No such file or directory
tar: 1: Cannot stat: No such file or directory
tar: 2: Cannot stat: No such file or directory
tar: 3": Cannot stat: No such file or directory
tar: "testdir: Cannot stat: No such file or directory
tar: 2: Cannot stat: No such file or directory
tar: 3: Cannot stat: No such file or directory
tar: 4/file: Cannot stat: No such file or directory
tar: 5: Cannot stat: No such file or directory
tar: 6: Cannot stat: No such file or directory
tar: 7": Cannot stat: No such file or directory
tar: "testfile": Cannot stat: No such file or directory
tar: Exiting with failure status due to previous errors
$

当我手动执行“echo”和运行命令时,没有这样的错误:

$ echo tar czvf backup_before_update.tgz -C ./test/ $(unzip -Z1 update.zip|grep -v \/$|sed -r 's/^/"/;s/$/"/'|paste -sd" ")
tar czvf backup_before_update.tgz -C ./test/ "testdir/file 1 2 3" "testdir 2 3 4/file 5 6 7" "testfile"
$ tar czvf backup_before_update.tgz -C ./test/ "testdir/file 1 2 3" "testdir 2 3 4/file 5 6 7" "testfile"
testdir/file 1 2 3
testdir 2 3 4/file 5 6 7
testfile
$ 

我可以使用 eval,它也可以:

$ eval $(echo tar czvf backup_before_update.tgz -C ./test/ $(unzip -Z1 update.zip|grep -v \/$|sed -r 's/^/"/;s/$/"/'|paste -sd" "))
testdir/file 1 2 3
testdir 2 3 4/file 5 6 7
testfile
$ eval $(echo tar czvf backup_before_update.tgz -C ./test/ $(unzip -Z1 update.zip|grep -v \/$|sed -r 's/^/"/;s/$/"/'))
testdir/file 1 2 3
testdir 2 3 4/file 5 6 7
testfile
$

即使所有给定的文件名都用双引号引起来,为什么第一个命令也会失败?

当您使用 set -x 打开调试(并使用 set - 关闭)时,您会看到 $(...) 的结果使用空格作为分隔符拆分为参数。在你的情况下(没有带换行符的文件名)当你创建一个文件列表时,你几乎完成了,每个文件都在一行上。 GNU tar 可以使用 -T 选项

从文件中读取
-T, --files-from=FILE
   Get names to extract or create from FILE.
   Unless  specified  otherwise,  the  FILE must contain a list of names separated by
   ASCII LF (i.e. one name per line).  The names read are handled the same way as
   command line arguments.

当您希望将 cmd 的结果作为文件处理时,您可以使用结构 <(cmd)

tar czvf backup_before_update.tgz -C ./test/ -T <(unzip -Z1 update.zip|grep -v \/$)