4

To make my environment deployable, I occasionally tar up some handy files and scripts:

tar -czvf env.tgz .vimrc .vim/ bin/lsl bin/s

I would like to add .bashrc to the mix, but I have some sensitive information in there so I maintain .bashrc-deploy which I can then simply rename once the tarball is on the new server. However, I would really like to have the tarball have the correct name .bashrc from the get-go so that I would not have to rename. I considered writing a script which would temporarily rename the files and make the tarball, like so:

#!/bin/bash
mv .bashrc .bashrc-real
mv .bashrc-deploy .bashrc
tar -czvf env.tgz .bashrc .vimrc .vim/ bin/lsl bin/s
mv .bashrc .bashrc-deploy
mv .bashrc-real .bashrc

However, does tar have any internal way of storing someFile with the name anotherName in the tarball?

dotancohen
  • 15,864

3 Answers3

5

With pax (the standard (POSIX) command to create tar archives) and bsdtar see the -s option:

pax -s '/\.bashrc-deploy/.bashrc/' -w -x ustar . | gzip > a.tar.gz

bsdtar -s '/\.bashrc-deploy/.bashrc/' -zcf a.tar.gz .

Note however, that the above would replace the .bashrc-deploy string with .bashrc in any file path of any member to be added to the archive. If you want to replace only the ./.bashrc-deploy in the current directory, you'd have to write it:

pax -s '|^\./\.bashrc-deploy$|./.bashrc|' -w -x ustar .

(though from reading the POSIX pax specification, I'm not sure it's guaranteed to work that way with every pax implementation. It should work with bsdtar though as there's only one implementation).

  • Interesting, thank you Stephane. I will look into pax and the BSD version of tar. – dotancohen Nov 13 '12 at 11:44
  • It should be noted that whilst pax is technically standardised by POSIX, many distributions don't include it in their base installation (Debian and Arch, to name the two I know for certain). – Chris Down Nov 13 '12 at 12:01
  • Also note that bsdtar is available on many Linux installations, such as an Arch default install (well, at least it was a year ago, I'm not using Arch anymore). IIRC, it's part of libarchive. – dubiousjim Nov 13 '12 at 14:01
  • @dubiousjim Yup, it's still standard in Arch. – Chris Down Nov 13 '12 at 18:13
  • @ChrisDown, thanks for the edit but I had to roll it back since at least with the pax and bsdtar implementations I have access to, the pattern is applied to the whole path, not the filename (so anchoring wouldn't work that way) and POSIX is not clear about that. – Stéphane Chazelas Nov 13 '12 at 22:04
  • @StephaneChazelas My bad. Surely you can at least have an EOL anchor? – Chris Down Nov 13 '12 at 22:07
4

One way you could do this is a chainload.

In .bashrc:

#!/bin/bash

# ...
# Non-private information
# ...

[[ -r ~/.bashrc-private ]] && . ~/.bashrc-private

Then put (only) your private stuff in ~/.bashrc-private and everything else in ~/.bashrc. Then just deploy ~/.bashrc.

Chris Down
  • 125,559
  • 25
  • 270
  • 266
  • Thank you, this is a far better solution as it does not require me to maintain two versions of .bashrc. Thank you! – dotancohen Nov 13 '12 at 11:23
  • Some tar have the option. See bsdtar and pax – Stéphane Chazelas Nov 13 '12 at 11:29
  • @StephaneChazelas And GNU tar, which is probably what the asker has. – Gilles 'SO- stop being evil' Nov 13 '12 at 22:01
  • Too bad the accepted answer doesn't answer the question at all. Such meta answers can be okay in forums, but IMO StackOverflow pages should discourage useless answers like these. – Ancurio Apr 05 '13 at 11:50
  • @Ancurio Yes, it was so useless that it was accepted by the OP. The OP asked the wrong question, he got the wrong answers. I am here to help, not play dumb to the actual needs of the person asking the question. – Chris Down Apr 05 '13 at 13:15
  • @ChrisDown OP got his answer, millions of people coming here through google remain clueless. – Ancurio Apr 05 '13 at 14:06
  • @Ancurio I am here to meet the needs of those who ask the questions primarily, and everyone else as an afterthought. I remain a little skeptical about your grandiose claim that "millions of people" have viewed this when the question has only been viewed by 170 people in 5 months. If you have a question that is not answered on this page, please ask it elsewhere. – Chris Down Apr 05 '13 at 14:37
4

With GNU tar (the default tar implementation on non-embedded Linux and on Cygwin):

tar czf env.tgz --transform 's/-deploy$//' .bashrc-deploy .profile …

This is also possible with pax, the POSIX replacement for cpio and tar, which unfortunately is missing from many default Linux installations, and also with BSD tar:

pax -w -x ustar '-s/-deploy$//' .bashrc-deploy .profile … | gzip >env.tgz
bsdtar -czf env.tgz '-s/-deploy$//' .bashrc-deploy .profile …

In all three cases, the s/REGEX/REPLACEMENT/ syntax is the same as ed or sed.


I question your approach. Having files with the same name but different contents on different machines is hard to maintain. Furthermore, it's easy to make a mistake if some files must remain private. My recommendation is to store your configuration files in subdirectories, and use symbolic links. For example, if .bashrc must be private and site-specific and .profile must be public and is the same everywhere:

.bashrc -> etc/local/private/.bashrc
.profile -> etc/.profile

Make etc/local a symbolic link to a directory whose name is site-dependent (e.g. ~/etc/home or ~/etc/work), ensure that ~/etc/private and ~/etc/*/private are only accessible by you, and you're set. You can deploy the whole ~/etc directory, and you'll only need to set the etc/local symbolic link after unzipping the archive (or, even better, checking out from version control).

For a file like .bashrc, which is probably mostly site-independent and public, split the file into two (or up to four) parts, public and private (plus site-specific files if necessary). Have the main part include the local parts:

if [ -e ~/etc/private/.bashrc ]; then . ~/etc/private/.bashrc; fi
if [ -e ~/etc/local/.bashrc ]; then . ~/etc/local/.bashrc; fi
if [ -e ~/etc/local/private/.bashrc ]; then . ~/etc/local/private/.bashrc; fi

In files which are written in a programming language, you can test the host name or domain name or other site-dependent characteristic dynamically, which lets you have a single file to maintain.

case $HOSTNAME in
  darkstar) alias foo=some-local-command;;
esac

It's a bit surprising to have confidential content in .bashrc. If you're defining environment variables, they belong in ~/.profile.

  • Thank you Gilles. In fact, the confidential information is in some aliases that I use so that I can quickly log into common remote servers. No passwords, but usernames and IP address don't need to get around either! As you have noticed Chris did also mention how to put the sensitive information in included files that are not synced, which really is the wisest choice. Thanks for showing me the replacement syntax, though, as a VIM user that is very intuitive! – dotancohen Nov 13 '12 at 22:58