7

I am trying to add a file to a tar archive from a program output without generating it on disk first. Think of a file VERSION, that is autogenerated, when the build script runs. I tried this but the dereferenced symlink is only a named pipe, not a regular file:

$ date +%s | \
  tar cf test.tar \
    --dereference \
    --transform="s#/proc/self/fd/0#VERSION#" \
    /proc/self/fd/0 \
    other_files \
    and_folders/

The result should be a file VERSION with a timestamp inside the tar archive w/o locally generating a file:

$ tar tf test.tar
VERSION
other_files
and_folders
Boldewyn
  • 75,918
  • 43
  • 139
  • 205

2 Answers2

1

I don't know a way to create a "fake" file entry in a JAR archive. I'd create a normal file, add it to the archive and then delete it afterwards.

You may want to try the option -A (or --concatenate), though. That would allow you to create the file in /tmp, add it to the TAR archive and then append the rest of the files in a second step. That way, you can create arbitrary paths for the VERSION file.

Aaron Digulla
  • 297,790
  • 101
  • 558
  • 777
  • Thanks! That's basically how I'm doing it right now. Doing a `mktemp`, adding it to the archive with `--transform=s/tempfile/VERSION/` and then deleting. I was just hoping to make this step a little more concise with some kind of pipe magic. – Boldewyn Nov 25 '14 at 19:11
  • That's the only way to do it because you can't give TAR the file name and it's content via pipes. `/proc/self/fd/0` doesn't work since `tar` archives links as special files instead of expanding their content. I'm also surprised that `--dereference` doesn't switch that off in this case. – Aaron Digulla Nov 26 '14 at 10:39
  • 1
    Well, `--dereference` does have an effect: Without, the packed `/proc/self/fd/0` remains a symlink, with it it's a named pipe (the type that `ls -F` appends a `|` to). But a packed pipe is of limited use... – Boldewyn Nov 29 '14 at 11:43
1

While it's true that tar works on files, that doesn't mean you have to create temporary files by yourself, and I would advice against it.

You can use process substitution for that (Bash supports that, Fish does as well in a slightly different syntax).

tar cvaf a.tgz <(echo 1.0.0) file1 file2 -P --transform 's:^/.*:VERSION:'

-P (--absolute-names) is here to identify the temporary file for name transformation to rename it. Hopefully other files are local.

If that's not the case and some other files are being added by absolute paths (which is probably not the common case), then you can either clarify the transformation regexp or use two-step solution with creating the archive first and then updating it (as Aaron pointed out).

eush77
  • 3,480
  • 21
  • 29
  • This suffers from the same problem as my `/proc` solution: `tar` packs a pipe, not a regular file. On unpacking, it says: `$ cat VERSION\ncat: VERSION: File or folder not found`. – Boldewyn Nov 29 '14 at 11:40
  • 1
    @Boldewyn This tends to be different across shells. Fish creates actual named pipes with `mkfifo` (e.g. `/tmp/.psub.O02RnmHZ5g`), and the proposed method works perfectly. Bash utilizes some magic files like `/dev/fd/63`. Unfortunately, there seems to be no built-in way to switch to `mkfifo` for process substitution in Bash. – eush77 Dec 12 '14 at 08:19
  • Interesting! OK, that would indeed work, but I'm bound to Bash here. – Boldewyn Dec 15 '14 at 08:40