Process substitution with pv results in empty file

238 Views Asked by At

I am having issues getting the pv command to work with tar using Bash process substitution.

I can use pv like this, and it works:

$ tar cvf - dir | pv > file.tar
dir/
dir/b
dir/a
  10KiB 0:00:00 [16.9MiB/s] [<=>                                 ]
$ ls -s file.tar 
12 file.tar

Using process substitution with cat also works:

$ tar cvf >(cat > file.tar) dir
dir/
dir/b
dir/a
$ ls -s file.tar 
12 file.tar

But this command results in an empty file.tar:

$ tar cvf >(pv > file.tar) dir
dir/
dir/b
dir/a
$ ls -s file.tar 
0 file.tar

I have also tried tar cvf >(pv - > file.tar) dir with the same result.

My goal is to have pv print out progress, and pipe the output of tar (i.e., the list of files and any errors) to other commands for additional processing. The first example command above only results in 2 output streams: stdout contains the binary tar data, and stderr contains both the list of files and any error messages. Using process substitution will result in 3 output streams: the binary tar data goes to the new process, stdout contains the list of files, and stderr contains any error messages.

Can I use the pv command with Bash process substitution, and if so, how?

I am using pv 1.6.0 and GNU bash, version 4.3.46(1)-release.

Interestingly, if I use strace to try and debug pv, it works:

$ tar cvf >(strace pv > file.tar) dir
dir/
dir/b
dir/a
execve("/usr/bin/pv", ["pv"], [/* 75 vars */]) = 0
brk(NULL)                               = 0x1eb8000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f46c9bac000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=123417, ...}) = 0
mmap(NULL, 123417, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f46c9b8d000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\t\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1864888, ...}) = 0
mmap(NULL, 3967392, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f46c95c0000
mprotect(0x7f46c977f000, 2097152, PROT_NONE) = 0
mmap(0x7f46c997f000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1bf000) = 0x7f46c997f000
mmap(0x7f46c9985000, 14752, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f46c9985000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f46c9b8c000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f46c9b8b000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f46c9b8a000
arch_prctl(ARCH_SET_FS, 0x7f46c9b8b700) = 0
mprotect(0x7f46c997f000, 16384, PROT_READ) = 0
mprotect(0x60d000, 4096, PROT_READ)     = 0
mprotect(0x7f46c9bae000, 4096, PROT_READ) = 0
munmap(0x7f46c9b8d000, 123417)          = 0
brk(NULL)                               = 0x1eb8000
brk(0x1ed9000)                          = 0x1ed9000
fstat(0, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
fstat(1, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
ioctl(2, TCGETS, {B38400 opost isig -icanon -echo ...}) = 0
ioctl(2, TCGETS, {B38400 opost isig -icanon -echo ...}) = 0
ioctl(2, TIOCGWINSZ, {ws_row=73, ws_col=178, ws_xpixel=0, ws_ypixel=0}) = 0
ioctl(2, TCGETS, {B38400 opost isig -icanon -echo ...}) = 0
ioctl(2, TCGETS, {B38400 opost isig -icanon -echo ...}) = 0
ioctl(2, SNDCTL_TMR_START or TCSETS, {B38400 opost isig -icanon -echo ...}) = 0
ioctl(2, TCGETS, {B38400 opost isig -icanon -echo ...}) = 0
rt_sigaction(SIGPIPE, {SIG_IGN, [], SA_RESTORER, 0x7f46c95f54b0}, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGTTOU, {0x408690, [], SA_RESTORER, 0x7f46c95f54b0}, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGTSTP, {0x408660, [], SA_RESTORER, 0x7f46c95f54b0}, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGCONT, {0x408710, [], SA_RESTORER, 0x7f46c95f54b0}, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGWINCH, {0x408620, [], SA_RESTORER, 0x7f46c95f54b0}, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGINT, {0x408640, [], SA_RESTORER, 0x7f46c95f54b0}, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGHUP, {0x408640, [], SA_RESTORER, 0x7f46c95f54b0}, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGTERM, {0x408640, [], SA_RESTORER, 0x7f46c95f54b0}, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGSYS, {SIG_IGN, [SYS], SA_RESTORER|SA_RESTART, 0x7f46c95f54b0}, {SIG_DFL, [], 0}, 8) = 0
geteuid()                               = 4841
stat("/tmp", {st_mode=S_IFDIR|S_ISVTX|0777, st_size=110592, ...}) = 0
msgget(0x500112e9, IPC_CREAT|0600)      = 2818048
fstat(0, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
fstat(1, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
ioctl(0, TCGETS, 0x7ffc1cd79860)        = -1 ENOTTY (Inappropriate ioctl for device)
fstat(0, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
getpid()                                = 29280
msgrcv(2818048, 0x7ffc1cd797e0, 568, 29280, IPC_NOWAIT) = -1 ENOMSG (No message of desired type)
mmap(NULL, 135168, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f46c9b69000
select(1, [0], [], NULL, {0, 90000})    = 1 (in [0], left {0, 89998})
splice(0, NULL, 1, NULL, 131072, SPLICE_F_MORE) = 10240
select(1, [0], [], NULL, {0, 90000})    = 1 (in [0], left {0, 89999})
splice(0, NULL, 1, NULL, 131072, SPLICE_F_MORE) = 0
read(0, "", 131072)                     = 0
write(2, "  10KiB 0:00:00 [  37MiB/s] [  <"..., 178  10KiB 0:00:00 [  37MiB/s] [  <=>                                                                                                                                               ]) = 178
)                       = 1
write(2, "\n", 1
)                       = 1
close(0)                                = 0
msgctl(2818048, IPC_RMID, 0x7ffc1cd79b30) = 0
ioctl(2, TCGETS, {B38400 opost isig -icanon -echo ...}) = 0
ioctl(2, SNDCTL_TMR_START or TCSETS, {B38400 opost isig -icanon -echo ...}) = 0
ioctl(2, TCGETS, {B38400 opost isig -icanon -echo ...}) = 0
rt_sigaction(SIGPIPE, {SIG_DFL, [], SA_RESTORER, 0x7f46c95f54b0}, NULL, 8) = 0
rt_sigaction(SIGTTOU, {SIG_DFL, [], SA_RESTORER, 0x7f46c95f54b0}, NULL, 8) = 0
rt_sigaction(SIGTSTP, {SIG_DFL, [], SA_RESTORER, 0x7f46c95f54b0}, NULL, 8) = 0
rt_sigaction(SIGCONT, {SIG_DFL, [], SA_RESTORER, 0x7f46c95f54b0}, NULL, 8) = 0
rt_sigaction(SIGWINCH, {SIG_DFL, [], SA_RESTORER, 0x7f46c95f54b0}, NULL, 8) = 0
rt_sigaction(SIGINT, {SIG_DFL, [], SA_RESTORER, 0x7f46c95f54b0}, NULL, 8) = 0
rt_sigaction(SIGHUP, {SIG_DFL, [], SA_RESTORER, 0x7f46c95f54b0}, NULL, 8) = 0
rt_sigaction(SIGTERM, {SIG_DFL, [], SA_RESTORER, 0x7f46c95f54b0}, NULL, 8) = 0
munmap(0x7f46c9b69000, 135168)          = 0
exit_group(0)                           = ?
+++ exited with 0 +++

$ ls -s file.tar 
12 file.tar
0

There are 0 best solutions below