3

We have this GNU tar command as shown:

$ tar -xjf /dev/st0 --to-command='sh -c '\''printf "%s\n" "$TAR_SIZE $TAR_REALNAME" >> "$TAR_ARCHIVE.sizes.txt"'\'

Is there any way we can get tar's PID inside of --to-command? Something like this:

$ [...] --to-command='sh -c '\''printf "%s\n" "$TAR_SIZE $TAR_REALNAME" >> "$TAR_ARCHIVE.sizes.$TAR_PID.txt"'\'

(note the addition of fictional $TAR_PID near the end)

I read the manpages of GNU tar 1.34 but see no relevant variables.

3
  • 1
    Have you tried dumping the environment using printenv in --to-command and seeing if there's anything relevant there?
    – muru
    Commented Jul 30 at 2:47
  • @muru I just ran it as --to-command=printenv and --to-command='sh -c printenv', both with echo $! right afterwards, and could not find the mentioned PID anywhere in printenv's output
    – leetbacoon
    Commented Jul 30 at 3:00
  • In any event, there are differences in the PID/PPID handling between the Linux and BSD families (the latter including Solaris and possibly Macs), so for thoroughness you should test on multiple OSes. Commented Jul 31 at 6:55

2 Answers 2

11

All POSIX sh implementations set the $PPID variable to the pid of the parent of the process that executed it, so:

tar -xvf foo.tgz --to-command='
  printf "%s\n" "$TAR_SIZE $TAR_REALNAME" >> "$TAR_ARCHIVE.sizes.$PPID"'

Note that that variable doesn't show up in the output of printenv as it's not exported to the environment (understandably as its value is only valid for the current shell), use the set command instead of the printenv command to list all shell variables (which includes a subset of those reported by printenv excluding the environment variables that cannot be mapped to shell variables).

$ tar cf - /etc/issue | env -i tar -xf - --to-command='set -x; printenv | grep -i pid; set | grep -i pid'
tar: Removing leading `/' from member names
+ printenv
+ grep -i pid
+ set
+ grep -i pid
PPID='27812'

If for some reason, your sh didn't set the $PPID variable, you could always do:

sh -c 'TAR_PID=$$ exec tar -xvf "$1" --to-command="$2"' sh foo.tgz '
  printf "%s\n" "$TAR_SIZE $TAR_REALNAME" >> "$TAR_ARCHIVE.sizes.$TAR_PID"'

Where, thanks to exec, it's the same process that runs sh and then tar, so we can make its pid ($$) available in the TAR_PID environment variable.

Now, since $TAR_ARCHIVE and $TAR_PID don't change, there's no need to reopen the file for every file and you can redirect all that output at once and use > instead of >>:

sh -c 'exec tar -xvf "$1" --to-command="$2" > "$1.sizes.$$' sh foo.tgz '
  printf "%s\n" "$TAR_SIZE $TAR_REALNAME"'

You can also get size and name information using the standard pax command.

gunzip < foo.tgz | pax -o listopt='%(size)u %(name)s\n'

Though the implementations commonly found on GNU/Linux systems in my experience don't implement that listopt option.

2
  • 1
    $PPID works really well, strange that it doesn't show up in printenv
    – leetbacoon
    Commented Jul 30 at 6:45
  • @leetbacoon, printenv lists the environment variables. sh does not export PPID to the environment (understandably). To list all shell variables, use set instead of printenv. Commented Jul 30 at 6:49
2

GNU Tar 1.35 on my Arch Linux system runs the command in a shell, so this outputs tar's PID for me:

tar ... --to-command='ps -o ppid= $$'

Example:

% tar xvf foo.tgz --to-command='ps -o ppid= $$' foo.c &
[1] 26000
foo.c
26000
[1]  + 26000 done       tar xvf foo.tgz --to-command='ps -o ppid= $$' foo.c

So maybe this should work:

tar --to-command='printf "%s\n" "$TAR_SIZE $TAR_REALNAME" >> "$TAR_ARCHIVE.sizes.$(ps -o ppid= $$).txt"'

Testing it out:

% tar xvf foo.tgz --to-command='printf "%s\n" "$TAR_SIZE $TAR_REALNAME" >> "$TAR_ARCHIVE.sizes.$(ps -o ppid= $$).txt"' &
[1] 26100
foo
foo.c
foo.compressed
[1]  + 26100 done       tar xvf foo.tgz
% cat foo.tgz.sizes.26100.txt
7568 foo
153 foo.c
148 foo.compressed
4
  • Could you please explain what ps is doing here? ____ This appears to work as expected, but I am now curious; how come the PID printed with ps and from the shell with & suffix do not match my subsequent echo $!?
    – leetbacoon
    Commented Jul 30 at 3:52
  • 1
    ppid is the column for the parent PID, and $$ is the current PID. So we have tar starting a shell, and that shell running ps. $$ will be that shell's PID, and its parent PID will be tar's PID. If that matches the one you see from your interactive shell with &, but not with $!, then something else, maybe a prompt customization or something like that, is running background commands and interfering with $!.
    – muru
    Commented Jul 30 at 4:10
  • I have alias tar='POSIXLY_CORRECT=1 tar' in my .bashrc, is that likely to interfere?
    – leetbacoon
    Commented Jul 30 at 4:17
  • No, I don't think so.
    – muru
    Commented Jul 30 at 4:24

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .