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

Time:12-28

In a directory there are files and sub-folders with spaces:

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

This is only test folder example to show the case, but on real environment this is huge folder with hundreds of files and size in total ca. 100GB.

I have a zip file with updates of some files from above folder. Before I unzip update file I would like to do selective backup of each file which will be replaced by this update.

The files in update.zip file are:

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

When I do just "echo" and run the command manually, there is no such error:

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

I can use eval and it works too:

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

Why the first command fails even if all given file names are in double quotes?

CodePudding user response:

When you turn on debug with set -x (and turn off with set -), you will see that the result of $(...) is split up in parameters using spaces as delimiters. In your case (no filenames with newline) you was almost done when you created a list of files, each on one line. GNU tar can read from a file with the -T option

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

You can use the construction <(cmd) when you want the result of cmd being handled as a file.

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