【问题标题】:tar using input list of files/folders with space in their namestar 使用名称中带有空格的文件/文件夹的输入列表
【发布时间】:2022-01-26 09:55:48
【问题描述】:

在一个目录下有文件和带有空格的子文件夹:

$ 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 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
$

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

【问题讨论】:

    标签: bash scripting


    【解决方案1】:

    当您使用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 \/$)
    

    【讨论】:

    • 谢谢。我是否还需要关心名称中带有空格的文件/文件夹,以便为 -T 构建此类列表?
    • 当我使用 tst/a file with a space 之类的文件和命令 tar czvf backup_before_update.tgz -C . -T &lt;(ls -1 */"a "*) 进行测试时,我没有发现任何问题。
    • 你能解释一下为什么没有 -T 它在类似的例子中不起作用,而使用 ls 命令的输入列表:unix.stackexchange.com/a/167724/243694 它确实如此。
    • 你试过set -x吗?问题是您需要 Bash 将字符串解析为不同的参数(每个参数都是不同的文件),并且当它解析 $() 返回的字符串时,将查看空格,而不是双引号。 for i in "a 1" "a 2" "a 3"; do echo "== $i =="; done 有效,但 for i in $(echo '"a 1" "a 2" "a 3"'); do echo "== $i =="; done 失败。在调用子进程之前处理双引号。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-10-23
    • 1970-01-01
    • 1970-01-01
    • 2018-04-23
    • 1970-01-01
    • 1970-01-01
    • 2018-04-18
    相关资源
    最近更新 更多