diff --git a/src/parallel b/src/parallel index 18374773..7d86dd47 100755 --- a/src/parallel +++ b/src/parallel @@ -182,10 +182,17 @@ sub pipe_tee_setup() { } # cat foo | tee fifo1 fifo2 fifo3 fifo4 fifo5 > /dev/null if(not fork()){ + # Test if tee supports --output-error=warn-nopipe + `echo | tee --output-error=warn-nopipe /dev/null >/dev/null 2>/dev/null`; + my $opt = $? ? "" : "--output-error=warn-nopipe"; # Let tee inherit our stdin # and redirect stdout to null open STDOUT, ">","/dev/null"; - exec "tee",@fifos; + if($opt) { + exec "tee", $opt, @fifos; + } else { + exec "tee", @fifos; + } } # For each fifo # (rm fifo1; grep 1) < fifo1 diff --git a/src/parallel.pod b/src/parallel.pod index 1260b7b0..d31187d3 100644 --- a/src/parallel.pod +++ b/src/parallel.pod @@ -1659,11 +1659,13 @@ Default: config =item B<-q> -Quote I. The command must be a simple command (see B) without redirections and without variable assignments. This -will quote the command line and arguments so special characters are -not interpreted by the shell. See the section QUOTING. Most people -will never need this. Quoting is disabled by default. +Quote I. If your command contains special characters that +should not be interpreted by the shell (e.g. ; \ | *), use B<--quote> to +escape these. The command must be a simple command (see B) without redirections and without variable assignments. + +See the section QUOTING. Most people will not need this. Quoting is +disabled by default. =item B<--no-run-if-empty> diff --git a/testsuite/tests-to-run/parallel-local-3s.sh b/testsuite/tests-to-run/parallel-local-3s.sh index aa4cd294..67e9093c 100644 --- a/testsuite/tests-to-run/parallel-local-3s.sh +++ b/testsuite/tests-to-run/parallel-local-3s.sh @@ -4,6 +4,33 @@ # Each should be taking 3-10s and be possible to run in parallel # I.e.: No race conditions, no logins +par_tee_with_premature_close() { + echo '--tee --pipe should send all data to all commands' + echo 'even if a command closes stdin before reading everything' + seq 1000000 | + parallel -k --tee --pipe \ + ::: 'sleep 1' 'sleep 2;wc' 'sleep 2;head' 'sleep 2;tail' + + # tee without --output-error=warn-nopipe support + cat > tmp/tee <<-EOF + #!/usr/bin/perl + + if(grep /output-error=warn-nopipe/, @ARGV) { + exit(1); + } + exec "/usr/bin/tee", @ARGV; + EOF + chmod +x tmp/tee + PATH=tmp:$PATH + # This gives incomplete output due to: + # * tee not supporting --output-error=warn-nopipe + # * sleep closes stdin before EOF + seq 1000000 | + parallel -k --tee --pipe \ + ::: 'sleep 1' 'sleep 2;wc' 'sleep 2;head' 'sleep 2;tail' + echo +} + par_maxargs() { echo '### Test -n and --max-args: Max number of args per line (only with -X and -m)' diff --git a/testsuite/wanted-results/parallel-local-3s b/testsuite/wanted-results/parallel-local-3s index 2042d6be..690efb66 100644 --- a/testsuite/wanted-results/parallel-local-3s +++ b/testsuite/wanted-results/parallel-local-3s @@ -1361,6 +1361,50 @@ par_sqlworker_hostname host par_sqlworker_hostname par_sqlworker_hostname par_sqlworker_hostname +par_tee_with_premature_close --tee --pipe should send all data to all commands +par_tee_with_premature_close even if a command closes stdin before reading everything +par_tee_with_premature_close 1000000 1000000 6888896 +par_tee_with_premature_close 1 +par_tee_with_premature_close 2 +par_tee_with_premature_close 3 +par_tee_with_premature_close 4 +par_tee_with_premature_close 5 +par_tee_with_premature_close 6 +par_tee_with_premature_close 7 +par_tee_with_premature_close 8 +par_tee_with_premature_close 9 +par_tee_with_premature_close 10 +par_tee_with_premature_close 999991 +par_tee_with_premature_close 999992 +par_tee_with_premature_close 999993 +par_tee_with_premature_close 999994 +par_tee_with_premature_close 999995 +par_tee_with_premature_close 999996 +par_tee_with_premature_close 999997 +par_tee_with_premature_close 999998 +par_tee_with_premature_close 999999 +par_tee_with_premature_close 1000000 +par_tee_with_premature_close 12773 12774 65536 +par_tee_with_premature_close 1 +par_tee_with_premature_close 2 +par_tee_with_premature_close 3 +par_tee_with_premature_close 4 +par_tee_with_premature_close 5 +par_tee_with_premature_close 6 +par_tee_with_premature_close 7 +par_tee_with_premature_close 8 +par_tee_with_premature_close 9 +par_tee_with_premature_close 10 +par_tee_with_premature_close 12765 +par_tee_with_premature_close 12766 +par_tee_with_premature_close 12767 +par_tee_with_premature_close 12768 +par_tee_with_premature_close 12769 +par_tee_with_premature_close 12770 +par_tee_with_premature_close 12771 +par_tee_with_premature_close 12772 +par_tee_with_premature_close 12773 +par_tee_with_premature_close 1277 par_test_X_with_multiple_source ### Test {} multiple times in different commands par_test_X_with_multiple_source echo 1 2 3 4 5 6 7 8 9 10 ; echo 1 2 3 4 5 6 7 8 9 10 par_test_X_with_multiple_source 1 2 3 4 5 6 7 8 9 10