I got an error when I append > /dev/null to tar command, anyone know what's going on in second example?
good:
tar -cvf $kname /var/www
bad:
tar -cvf $kname /var/www > /dev/null
error:tar: Removing leading `/' from member names
The "good" version is also displaying the same message you've just missed it.
If you don't like the behaviour, search for "leading", in manual. First hit:
-P, --absolute-names
don't strip leading '/'s from file names
This is because your file ($kname) has leading /.
To fix that, you may specify -C to change the directory, instead of specifying full path of the archive file.
It might be best to leave your files without the '/' in the backup and just ignore the error message. Tar does this as a safety precaution, because if you untar the file, it will automatically place the files back in the original directory. This can be dangerous and most people want to avoid this. Personally, I would be happy with the fact that it removed the '/' and then your restore will be relative and not absolute directory path. Then you can manually move the files into the right place, or a different place. Just posting this so people are aware and don't inadvertently replace their original files.
my version of tar does not extract an archive created with -P (--absolute-names) to the original location. this is only true for untar with argument -P
Related
With PHP I am using exec("tar -xf archive.tar -C /home/user/target/folder") to extract the contents of a specific archive (archive.tar) into the target directory (/home/user/target/folder), so that all existing contents of the target directory will be overwritten by the new ones that are contained in the archive.
It works fine and all files in the target directory are being overwritten after extract, but there is one directory in the archive that I would like to omit (from extracting and thus overwriting the existing one in the target folder)...
For example, the archive.tar contains:
folderA/
folderB/
folderC/
folderD/
fileA.php
fileB.php
fileC.xml
How could I extract (and overwrite) all except (for example) folderC/? In other words, I want folderC and its contents to remain intact in the user's directory and not be overwritten by the one contained in the tar archive.
Any suggestions?
(Tar on the hosting server is GNU version 1.23.)
You can use '--exclude' to omit a folder:
tar -xf archive.tar -C /home/user/target/folder" --exclude="folderC"
There is the --exclude PATTERN option in the tar tool.
Check: tar on linuxcommand.org
To be on the safe side, you could remove all write permissions from the folder. For example:
$ chmod 000 folderC/
An then do a normal tar extract (as regular user). You'll get some error messages on console, but your folder will remain untouched.... At the end of the tar, change back your folder original permissions. For example:
$ chmod 775 folderC/
Of course '--exclude' tar option is the right solution to this particular problem, but, if you are not completely 100% sure about a command syntax, and yor're handling critical data, my solution puts you on the safe side :-).
Write --exclude='./folder' at the beginning of the tar command.
In your case that is,
exec("tar -x --exclude='./C' -f archive.tar -C /home/user/target/folder")
Have got a problem executing the command as below:
tar -xvf arch.tar.gz -s '/^bundle//'
Could be the
-s '/^bundle//'
is a problem as I've got errors like:
$ tar -xvf arch.tar.gz -s '/^bundle//'
tar: /^bundle: Not found in archive
tar: Exiting with failure status due to previous errors
The tried to run the command under Cygwin/Win10.
It's part of the longer script but I'm not sure what was the idea of original author. Archive does include the 'bundle' folder inside... and it's the only first level file there.
Thank you in advance :)
-s does not mean to do a substitution, which seems to be how you're trying to use it. You probably want --xform='s/^bundle//'
-s has the following entry in the help listing:
-s, --preserve-order, --same-order
member arguments are listed in the same order as
the files in the archive
With your code it's actually trying to find a file with the name /^bundle// which does not exist, even if bundle does. Also, the --xform option I gave will rewrite the names of files to strip the string bundle from the front. If you are just trying to not extract the file bundle you would want the flag --exclude='bundle'
In this case, if bundle is a top level directory in the archive, and it's the only one, you could also use the flag --strip-components=1, though this would get rid of all the top level directories, so might not be exactly what you want depending on your archive
Thanks all,
Problem solved other, then 'tar', way but for those who may be interested here is the answer I have found on the web:
If you are developing on Linux, or using GNU tar, this command should work:
tar -xvf arch.tar.gz --transform 's|^bundle/||'
For Mac or BSD-based operating systems:
tar -xvf arch.tar.gz -s '/^bundle//'
Yes, the idea was to remove the /bundle/ folder from files paths.
Let's say I'm trying to tar.gz all the files and folders in /usr/local/bin/data/*
The file name would be data-2015-10-01.tar.gz. When I untar it, is it possible that the root directory would be data-2015-10-01 followed by the contents of whatever is inside of data/* ?
If not, how can I tar /usr/local/bin/data/* but start at the /data/ folder level?
I can't do this unfortunately since the program spits out /usr/local/bin/data/ and I'm unable to change it.
cd /usr/local/bin
tar ... /data/*
There are a couple of ways to do what I think you're trying to accomplish. First, you can use the -C option to tar when creating the archive. That changes tar's current working directory to that directory before creating the archive. Not strictly required in your case, but probably helpful.
# tar -C /usr/local/bin -czf data-2015-10-01.tar.gz data/*
That at least gets you to a single directory named data. If you have control of the extraction (manually or via a script you provide to whomever is unpacking this), then you can do something like this on the extraction:
# mkdir -f data-2015-10-01 && tar -C data-2015-10-01 --strip-components=1 -xzf data-2015-10-01.tar.gz
This will remove the first path, which is "data" and extract everything from there into the directory which is your current working directory, data-2015-10-01. So, it isn't specifically tar that's doing the renaming, but you will effectively end up with the same result.
I've accomplished something similar with a symlink. This is not a great solution if you have (or might have) symlinks in the directory structure you're trying to archive. I have to say that I prefer #geis' solution to strip out the top-level directory on extract, but this gives you another option.
ln -s /usr/local/bin/data data-2015-10-01
tar -cvhf data-2015-10-01.tar.gz data-2015-10-01/
rm data-2015-10-01
(Note the additional -h option in the tar invocation.)
I'm passing a tar command to shell executor in an application. But it seems that my tar syntax is incorrect. (This is Windows (bsdtar command) but works the same as Linux as far as I know; I can also test on Linux if need be.)
I'm trying to tar gz everything up all files ending in ext without storing the full path in my tar file.
tar -cvzf test.tar.gz -C C:/mydir/toTar/ *.ext
I get an error:
tar: *.ext: Cannot stat: No such file or directory
I can give the whole path but then my tar will contain C->mydir->toTar->. I just want the files, not mydir and toTar in the result.
So far only thing that is close to what I want is . instead of *.ext, but that tars other things too, which I obviously don't want.
The problem is that * is a wildcard character that is expanded by the shell, but you are bypassing the shell and calling tar directly. The tar command is looking for one file which is named literally *.ext and it does not exist.
Your options are:
Expand the list of files in your own code and pass that list to tar.
Call the shell from your code by calling something like /bin/sh -c tar ...
With option 2 there may be security implications -- if the shell sees something it thinks is a command, it will run it. Option 1 is therefore safer, but it's up to you which makes more sense.
I am befuddled by how you're using dos-style paths in an apparently linux-like context. But this is how I'd do it. Hopefully the concept is clear if the details may be incorrect.
cd C:/mydir/toTar/
mkdir ~/tmpwork
find . -name '*.ext' > ~/tmpwork/extfiles
tar czvfT ~/tmpwork/test.tar.gz ~/tmpwork/extfiles
rm ~/tmpfiles/extfiles
There is no way around the shell expansion without using pipes, etc.
I want to update an existing tar file with newer files.
At GNU, I read:
4.2.3 Updating an Archive
In the previous section, you learned how to use ‘--append’ to add a
file to an existing archive. A related operation is ‘--update’ (‘-u’).
The ‘--update’ operation updates a tar archive by comparing the date
of the specified archive members against the date of the file with the
same name. If the file has been modified more recently than the
archive member, then the newer version of the file is added to the
archive (as with ‘--append’).
However,
When I run my tar update command, the files are appended even though their modification dates are exactly the same. I want to ONLY append where modification dates of files to be tarred are newer than those already in the tar...
tar -uf ./tarfile.tar /localdirectory/ >/dev/null 2>&1
Currently, every time I update, the tar doubles in size...
The update you describe implies that the file within the archive is replaced. If the new copy is smaller than what's in the archive, it could be directly rewritten. If the new copy however is larger, tar would have to zero the existing archive entry and append. Such updates would leave runs of '\0's or other unused bytes, so any normal computer user would want that such sections are removed, which would be done by "moving up" bytes comprising the archive contents towards the start of the file (think C's memmove).
Such an in-place move operation however, which would involve seek-read-seek-write cycles, is costly, especially when you look at it in the context of tapes — which tar was designed for originally —, i.e. devices with a seek performance that is not comparable to harddisks. You'd wear out the tape rather quickly with such move ops. Oh and of course, WORM devices don't support this move op either.
If you do not want to use the "-P" switch tar -u... works correctly if the current directory is the parent directory of the one we are going to update, and the path to this directory in the tar command will not be an absolute path.
For exmple:
We want to update catalog /home/blabla/Dir. We do it like that:
cd /home/blabla
tar -u -f tarfile.tar Dir
In general, the update must be made from the same place as the creation, so that the paths agree.
It is also possible:
cd /home/blabla/Dir
tar-u -f /path/to/tarfile.tar .
You may simply create (instead of update) the archive each time:
tar -cvpf tarfile.tar *
This will solve the problem of your archive doubling in size each time. But of course, it is generating the whole archive every time.
By default tar strips the leading / from member names, but it does this after deciding what needs to be updated.
Therefore if you are archiving an absolute path, you either need to cd / and use relative paths, or add the -P/--absolute-names option.
cd /
tar -uf "$OLDPWD/tarfile.tar" localdirectory/ >/dev/null 2>&1
tar -cPf tarfile.tar /localdirectory/ >/dev/null 2>&1
tar -uPf tarfile.tar /localdirectory/ >/dev/null 2>&1
However, the updated items will still be appended. A tar (tape archive) file cannot be modified excpet by appending.
Warning! When speaking about "dates" it means any date, and that includes the access time.
Should your files have been accessed in any such way (a simple ls -l is enough) then tar is right to do what it does!
You need to find another way to do what you want. Probably use a sentinel file and see if its modification date is less than the files you wish to append.