parallel: sub wrapper implemented. Passed most of the testsuite.

This commit is contained in:
Ole Tange 2014-10-24 11:30:39 +02:00
parent 2f9dc0b034
commit 2ff435caea
9 changed files with 170 additions and 179 deletions

View file

@ -225,53 +225,18 @@ cc:Tim Cuthbertson <tim3d.junk@gmail.com>,
Ryoichiro Suzuki <ryoichiro.suzuki@gmail.com>, Ryoichiro Suzuki <ryoichiro.suzuki@gmail.com>,
Jesse Alama <jesse.alama@gmail.com> Jesse Alama <jesse.alama@gmail.com>
Subject: GNU Parallel 20141022 ('Shellshock') released Subject: GNU Parallel 20141122 ('') released
GNU Parallel 20141022 ('Shellshock') has been released. It is available for download at: http://ftp.gnu.org/gnu/parallel/ GNU Parallel 20141122 ('') has been released. It is available for download at: http://ftp.gnu.org/gnu/parallel/
Shellshock has also hit GNU Parallel. It is not a security issue, per se (the security issue was in Bash), but Bash's solution affects --env when exporting a function.
Haiku of the month: Haiku of the month:
Shellshock pain hits us. <<>>
Dash dash env is affected.
Upgrade Parallel.
-- Ole Tange
(Last month's haiku was by Malcolm Cook) A central piece of command generation was rewritten making this release alpha quality.
New in this release: New in this release:
* --env was changed to deal with Bash's new way of exporting a function.
* GNU Parallel was cited in: Exclusion of cosmic rays in protoplanetary disks. II. Chemical gradients and observational signatures http://iopscience.iop.org/0004-637X/794/2/123/article
* GNU Parallel was cited in: Application of Machine Learning to Algorithm Selection for TSP http://www.dbai.tuwien.ac.at/staff/musliu/art_ictai_cam.pdf
* GNU Parallel was cited in: Performance Models for LTE-Advanced Random Access http://repository.asu.edu/attachments/137242/content/Tyagi_asu_0010E_14116.pdf
* GNU Parallel was used (unfortunately without citation) in: De Novo Insertions and Deletions of Predominantly Paternal Origin Are Associated with Autism Spectrum Disorder http://www.cell.com/cms/attachment/2019079667/2039310868/mmc1.pdf
* GNU Parallel was determined 'popular' by Statistical Analysis of Popular Open Source Software Projects and Their Communities http://andiwre.itmaranatha.org/prosiding/ICITEE2014/PaperAndiWRE-ICITEE2014.pdf
* GNU Parallel is demonstrated in: Data Science at the Command Line: Facing the Future with Time-Tested Tools
* GNU Parallel was covered in a talk at Sydney Perl Mongers group http://www.openfusion.net/talks/pwp/#24
* GNU Parallel and how to get started with it http://www.jduck.net/blog/2014/09/30/gnu-paralell/
* Behat/Selenium/Parallel http://jaffamonkey.com/behat-selenium-parallel/
* Comparing Golang, Scala, Elixir and Ruby for ETL http://www.dimroc.com/2014/09/29/etl-language-showdown/
* Parallelizing Batch Jobs for Fun and Profit http://mikeseidle.com/tech/programming/2013/03/parallelizing-batch-jobs
* Assemble a list of which of these hosts are up or down http://opsfun.wordpress.com/2014/03/31/gnu-parallel/
* Running commands on many nodes simultaneously http://opsfun.wordpress.com/2014/03/31/19/
* Ubuntu 13.04でGNU ParallelをGNUモードで動かす http://qiita.com/YusukeSuzuki@github/items/7b96b5876bf980f21e85
* Bug fixes and man page updates. * Bug fixes and man page updates.
GNU Parallel - For people who live life in the parallel lane. GNU Parallel - For people who live life in the parallel lane.

View file

@ -24,7 +24,7 @@
use strict; use strict;
use Getopt::Long; use Getopt::Long;
$Global::progname="niceload"; $Global::progname="niceload";
$Global::version = 20141022; $Global::version = 20141023;
Getopt::Long::Configure("bundling","require_order"); Getopt::Long::Configure("bundling","require_order");
get_options_from_array(\@ARGV) || die_usage(); get_options_from_array(\@ARGV) || die_usage();
if($opt::version) { if($opt::version) {
@ -886,4 +886,4 @@ sub io_status_darwin {
return ::min($io, 10); return ::min($io, 10);
} }
$::exitsignal = $::exitstatus = 0; # Dummy $::exitsignal = $::exitstatus = $opt::battery = 0; # Dummy

View file

@ -101,17 +101,17 @@ B<--noswap> will set both B<--start-noswap> and B<run-noswap>.
Sets niceness. See B<nice>(1). Sets niceness. See B<nice>(1).
=item B<-p> I<PID> (beta testing) =item B<-p> I<PID>
=item B<--pid> I<PID> (beta testing) =item B<--pid> I<PID>
Process ID of process to suspend. You can specify multiple process IDs Process ID of process to suspend. You can specify multiple process IDs
with multiple B<-p> I<PID>. with multiple B<-p> I<PID>.
=item B<--prg> I<program> (beta testing) =item B<--prg> I<program>
=item B<--program> I<program> (beta testing) =item B<--program> I<program>
Name of running program to suspend. You can specify multiple programs Name of running program to suspend. You can specify multiple programs
with multiple B<--prg> I<program>. with multiple B<--prg> I<program>.
@ -141,7 +141,7 @@ Run limit. The running program will be slowed down if the system is
above the limit. See: B<--io>, B<--load>, B<--mem>, B<--noswap>. above the limit. See: B<--io>, B<--load>, B<--mem>, B<--noswap>.
=item B<--sensor> I<sensor program> (beta testing) =item B<--sensor> I<sensor program>
Read sensor. Use I<sensor program> to read a sensor. Read sensor. Use I<sensor program> to read a sensor.

View file

@ -123,8 +123,7 @@ if($opt::eta or $opt::bar) {
$Global::JobQueue->total_jobs(); $Global::JobQueue->total_jobs();
} }
if($opt::pipepart) { if($opt::pipepart) {
@Global::cat_partials = @Global::cat_partials = map { pipe_part_files($_) } @opt::a;
map { pipe_part_files($_) } @opt::a;
# Unget the command as many times as there are parts # Unget the command as many times as there are parts
$Global::JobQueue->{'commandlinequeue'}->unget( $Global::JobQueue->{'commandlinequeue'}->unget(
map { $Global::JobQueue->{'commandlinequeue'}->get() } @Global::cat_partials map { $Global::JobQueue->{'commandlinequeue'}->get() } @Global::cat_partials
@ -772,7 +771,7 @@ sub get_options_from_array {
sub parse_options { sub parse_options {
# Returns: N/A # Returns: N/A
# Defaults: # Defaults:
$Global::version = 20141022; $Global::version = 20141023;
$Global::progname = 'parallel'; $Global::progname = 'parallel';
$Global::infinity = 2**31; $Global::infinity = 2**31;
$Global::debug = 0; $Global::debug = 0;
@ -5368,6 +5367,97 @@ sub total_failed {
return ($total_failures); return ($total_failures);
} }
sub wrapped {
# Wrap command with:
# * --shellquote
# * --nice
# * --cat
# * --fifo
# * --sshlogin
# * --pipepart (@Global::cat_partials)
# * --pipe
# * --tmux
# The ordering of the wrapping is important:
# * --nice/--cat/--fifo should be done on the remote machine
# * --pipepart/--pipe should be done on the local machine inside --tmux
# Uses:
# $Global::envvar
# $opt::shellquote
# $opt::nice
# $Global::shell
# $opt::cat
# $opt::fifo
# @Global::cat_partials
# $opt::pipe
# $opt::tmux
# Returns:
# $self->{'wrapped'} = the command wrapped with the above
my $self = shift;
if(not defined $self->{'wrapped'}) {
my $command = $Global::envvar.$self->replaced();
if($opt::shellquote) {
# Prepend echo
# and quote twice
$command = "echo " .
::shell_quote_scalar(::shell_quote_scalar($command));
}
if($opt::nice) {
# Prepend \nice -n19 $SHELL -c
# and quote.
# The '\' before nice is needed to avoid tcsh's built-in
$command = '\nice'. " -n". $opt::nice. " ".
$Global::shell. " -c ".
::shell_quote_scalar($command);
}
if($opt::cat) {
# Prepend 'cat > {};'
# Append '_EXIT=$?;(rm {};exit $_EXIT)'
$command =
$self->{'commandline'}->replace_placeholders(["cat > \257<\257>; "], 0, 0).
$command.
$self->{'commandline'}->replace_placeholders(
["; _EXIT=\$?; rm \257<\257>; exit \$_EXIT"], 0, 0);
} elsif($opt::fifo) {
# Prepend 'mkfifo {}; ('
# Append ') & _PID=$!; cat > {}; wait $_PID; _EXIT=$?;(rm {};exit $_EXIT)'
$command =
$self->{'commandline'}->replace_placeholders(["mkfifo \257<\257>; ("], 0, 0).
$command.
$self->{'commandline'}->replace_placeholders([") & _PID=\$!; cat > \257<\257>; ",
"wait \$_PID; _EXIT=\$?; ",
"rm \257<\257>; exit \$_EXIT"],
0,0);
}
# Wrap with ssh + tranferring of files
$command = $self->sshlogin_wrap($command);
if(@Global::cat_partials) {
# Prepend:
# < /tmp/foo perl -e 'while(@ARGV) { sysseek(STDIN,shift,0) || die; $left = shift; while($read = sysread(STDIN,$buf, ($left > 32768 ? 32768 : $left))){ $left -= $read; syswrite(STDOUT,$buf); } }' 0 0 0 11 |
$command = (shift @Global::cat_partials). "|". "(". $command. ")";
} elsif($opt::pipe) {
# Prepend EOF-detector to avoid starting $command if EOF.
# The $tmpfile might exist if run on a remote system - we accept that risk
my ($dummy_fh, $tmpfile) = ::tmpfile(SUFFIX => ".chr");
# Unlink to avoid leaving files if --dry-run or --sshlogin
unlink $tmpfile;
$command =
# Exit value:
# empty input = true
# some input = exit val from command
qq{ sh -c 'dd bs=1 count=1 of=$tmpfile 2>/dev/null'; }.
qq{ test \! -s "$tmpfile" && rm -f "$tmpfile" && exec true; }.
qq{ (cat $tmpfile; rm $tmpfile; cat - ) | }.
"($command);";
}
if($opt::tmux) {
# Wrap command with 'tmux'
$command = $self->tmux_wrap($command);
}
$self->{'wrapped'} = $command;
}
return $self->{'wrapped'};
}
sub set_sshlogin { sub set_sshlogin {
my $self = shift; my $self = shift;
my $sshlogin = shift; my $sshlogin = shift;
@ -5382,32 +5472,22 @@ sub sshlogin {
sub sshlogin_wrap { sub sshlogin_wrap {
# Wrap the command with the commands needed to run remotely # Wrap the command with the commands needed to run remotely
# Uses: # Returns:
# @Global::cat_partials # $self->{'sshlogin_wrap'} = command wrapped with ssh+transfer commands
# $Global::envvar
my $self = shift; my $self = shift;
my $command = shift;
if(not defined $self->{'sshlogin_wrap'}) { if(not defined $self->{'sshlogin_wrap'}) {
my $sshlogin = $self->sshlogin(); my $sshlogin = $self->sshlogin();
my $sshcmd = $sshlogin->sshcommand(); my $sshcmd = $sshlogin->sshcommand();
my $serverlogin = $sshlogin->serverlogin(); my $serverlogin = $sshlogin->serverlogin();
my $next_command_line = $Global::envvar.$self->replaced();
my ($pre,$post,$cleanup)=("","",""); my ($pre,$post,$cleanup)=("","","");
if($serverlogin eq ":") { if($serverlogin eq ":") {
if(@Global::cat_partials) { # No transfer neeeded
# Prepend: $self->{'sshlogin_wrap'} = $command;
# < /tmp/foo perl -e 'while(@ARGV) { sysseek(STDIN,shift,0) || die; $left = shift; while($read = sysread(STDIN,$buf, ($left > 32768 ? 32768 : $left))){ $left -= $read; syswrite(STDOUT,$buf); } }' 0 0 0 11 |
$self->{'sshlogin_wrap'} = (shift @Global::cat_partials). "|".
"(". $next_command_line. ")";
} else {
$self->{'sshlogin_wrap'} = $next_command_line;
}
} else { } else {
# --transfer # --transfer
$pre .= $self->sshtransfer(); $pre .= $self->sshtransfer();
if(@Global::cat_partials) {
$pre .= (shift @Global::cat_partials)."|";
}
# --return # --return
$post .= $self->sshreturn(); $post .= $self->sshreturn();
# --cleanup # --cleanup
@ -5474,7 +5554,7 @@ sub sshlogin_wrap {
. "$sshcmd $ssh_options $serverlogin $parallel_env " . "$sshcmd $ssh_options $serverlogin $parallel_env "
. $remote_pre . $remote_pre
# . ::shell_quote_scalar($signal_script . ::shell_quote_scalar($next_command_line)) # . ::shell_quote_scalar($signal_script . ::shell_quote_scalar($next_command_line))
. ::shell_quote_scalar($next_command_line) . ::shell_quote_scalar($command)
. ";" . ";"
. $post); . $post);
} }
@ -5692,7 +5772,7 @@ sub start {
# job-object or undef if job not to run # job-object or undef if job not to run
my $job = shift; my $job = shift;
# Get the shell command to be executed (possibly with ssh infront). # Get the shell command to be executed (possibly with ssh infront).
my $command = $job->sshlogin_wrap(); my $command = $job->wrapped();
if($Global::interactive or $Global::stderr_verbose) { if($Global::interactive or $Global::stderr_verbose) {
if($Global::interactive) { if($Global::interactive) {
@ -5733,21 +5813,6 @@ sub start {
$job->seq(), "): $command\n"); $job->seq(), "): $command\n");
if($opt::pipe) { if($opt::pipe) {
my ($stdin_fh); my ($stdin_fh);
# Wrap command with end-of-file detector,
# so we do not spawn a program if there is no input.
# Exit value:
# empty input = true
# some input = exit val from command
my ($dummy_fh, $tmpfile) = ::tmpfile(SUFFIX => ".chr");
$command = qq{
sh -c 'dd bs=1 count=1 of=$tmpfile 2>/dev/null';
test \! -s "$tmpfile" && rm -f "$tmpfile" && exec true;
(cat $tmpfile; rm $tmpfile; cat - ) | } .
"($command);";
if($opt::tmux) {
$command = $job->tmux_wrap($command);
}
# The eval is needed to catch exception from open3 # The eval is needed to catch exception from open3
eval { eval {
$pid = ::open3($stdin_fh, ">&OUT", ">&ERR", $Global::shell, "-c", $command) || $pid = ::open3($stdin_fh, ">&OUT", ">&ERR", $Global::shell, "-c", $command) ||
@ -5760,9 +5825,6 @@ sub start {
# Give STDIN to the first job if using -a (but only if running # Give STDIN to the first job if using -a (but only if running
# locally - otherwise CTRL-C does not work for other jobs Bug#36585) # locally - otherwise CTRL-C does not work for other jobs Bug#36585)
*IN = *STDIN; *IN = *STDIN;
if($opt::tmux) {
$command = $job->tmux_wrap($command);
}
# The eval is needed to catch exception from open3 # The eval is needed to catch exception from open3
eval { eval {
$pid = ::open3("<&IN", ">&OUT", ">&ERR", $Global::shell, "-c", $command) || $pid = ::open3("<&IN", ">&OUT", ">&ERR", $Global::shell, "-c", $command) ||
@ -5776,9 +5838,6 @@ sub start {
open(my $devtty_fh, "<", "/dev/tty")) { open(my $devtty_fh, "<", "/dev/tty")) {
# Give /dev/tty to the command if no one else is using it # Give /dev/tty to the command if no one else is using it
*IN = $devtty_fh; *IN = $devtty_fh;
if($opt::tmux) {
$command = $job->tmux_wrap($command);
}
# The eval is needed to catch exception from open3 # The eval is needed to catch exception from open3
eval { eval {
$pid = ::open3("<&IN", ">&OUT", ">&ERR", $Global::shell, "-c", $command) || $pid = ::open3("<&IN", ">&OUT", ">&ERR", $Global::shell, "-c", $command) ||
@ -5788,9 +5847,6 @@ sub start {
1; 1;
}; };
} else { } else {
if($opt::tmux) {
$command = $job->tmux_wrap($command);
}
# The eval is needed to catch exception from open3 # The eval is needed to catch exception from open3
eval { eval {
$pid = ::open3(::gensym, ">&OUT", ">&ERR", $Global::shell, "-c", $command) || $pid = ::open3(::gensym, ">&OUT", ">&ERR", $Global::shell, "-c", $command) ||
@ -5830,7 +5886,7 @@ sub tmux_wrap {
close $fh; close $fh;
unlink $tmpfile; unlink $tmpfile;
my $visual_command = $self->replaced(); my $visual_command = $self->replaced();
my $title = ::undef_as_empty($self->{'commandline'}->replace_placeholders(["\257<\257>"],0,0)).""; my $title = $visual_command;
# ; causes problems # ; causes problems
# ascii 194-245 annoys tmux # ascii 194-245 annoys tmux
$title =~ tr/[\011-\016;\302-\365]//d; $title =~ tr/[\011-\016;\302-\365]//d;
@ -5846,11 +5902,12 @@ sub tmux_wrap {
return "mkfifo $tmpfile; $tmux ". return "mkfifo $tmpfile; $tmux ".
# Run in tmux # Run in tmux
::shell_quote_scalar( ::shell_quote_scalar(
"(".$actual_command.');(echo $?$status;echo 255) >'.$tmpfile.";". "(".$actual_command.');(echo $?$status;echo 255) >'.$tmpfile."&".
"echo ".::shell_quote_scalar($visual_command).";". "echo ".::shell_quote_scalar($visual_command).";".
"echo \007Job finished at: `date`;sleep 10"). "echo \007Job finished at: `date`;sleep 10").
# Run outside tmux # Run outside tmux
"; exit `perl -ne 'unlink $ARGV; 1..1 and print' $tmpfile;rm $tmpfile` "; # Read the first line from the fifo and use that as status code
"; exit `perl -ne 'unlink \$ARGV; 1..1 and print' $tmpfile` ";
} }
sub is_already_in_results { sub is_already_in_results {
@ -5924,7 +5981,7 @@ sub print {
$Global::grouped or return; $Global::grouped or return;
# Check for disk full # Check for disk full
exit_if_disk_full(); exit_if_disk_full();
my $command = $self->sshlogin_wrap(); my $command = $self->wrapped();
if(($opt::dryrun or $Global::verbose) and $Global::grouped if(($opt::dryrun or $Global::verbose) and $Global::grouped
and and
@ -6256,7 +6313,7 @@ sub populate {
my $max_len = $Global::minimal_command_line_length || Limits::Command::max_length(); my $max_len = $Global::minimal_command_line_length || Limits::Command::max_length();
if($opt::cat or $opt::fifo) { if($opt::cat or $opt::fifo) {
# Get a tempfile name # Generate a tempfile name that will be used as {}
my($outfh,$name) = ::tmpfile(SUFFIX => ".pip"); my($outfh,$name) = ::tmpfile(SUFFIX => ".pip");
close $outfh; close $outfh;
# Unlink is needed if: ssh otheruser@localhost # Unlink is needed if: ssh otheruser@localhost
@ -6484,6 +6541,8 @@ sub header_indexes_sorted {
} }
sub len { sub len {
# Uses:
# $opt::shellquote
# The length of the command line with args substituted # The length of the command line with args substituted
my $self = shift; my $self = shift;
my $len = 0; my $len = 0;
@ -6546,63 +6605,18 @@ sub replaced {
# Uses: # Uses:
# $Global::noquote # $Global::noquote
# $Global::quoting # $Global::quoting
# $opt::cat
# $opt::fifo
# $opt::nice
# $opt::shellquote
# Returns: # Returns:
# $replaced = command with place holders replaced and prepended # $replaced = command with place holders replaced and prepended
my $self = shift; my $self = shift;
if(not defined $self->{'replaced'}) { if(not defined $self->{'replaced'}) {
# Don't quote arguments if the input is the full command line # Don't quote arguments if the input is the full command line
my $quote_arg = $Global::noquote ? 0 : not $Global::quoting; my $quote_arg = $Global::noquote ? 0 : not $Global::quoting;
my $cmdstring = $self->replace_placeholders($self->{'command'},$Global::quoting,$quote_arg); $self->{'replaced'} = $self->replace_placeholders($self->{'command'},$Global::quoting,$quote_arg);
if (length($cmdstring) != $self->len()) { my $len = length $self->{'replaced'};
::debug("length", length $cmdstring, " != ", $self->len(), " ", $cmdstring, "\n"); if ($len != $self->len()) {
::debug("length", $len, " != ", $self->len(), " ", $self->{'replaced'}, "\n");
} else { } else {
::debug("length", length $cmdstring, " == ", $self->len(), " ", $cmdstring, "\n"); ::debug("length", $len, " == ", $self->len(), " ", $self->{'replaced'}, "\n");
}
if($opt::cat) {
# Prepend 'cat > {};'
# Append '_EXIT=$?;(rm {};exit $_EXIT)'
$self->{'replaced'} =
$self->replace_placeholders(["cat > \257<\257>; ", $cmdstring,
"; _EXIT=\$?; rm \257<\257>; exit \$_EXIT"],
0,0);
} elsif($opt::fifo) {
# Prepend 'mkfifo {}; ('
# Append ') & _PID=$!; cat > {}; wait $_PID; _EXIT=$?;(rm {};exit $_EXIT)'
$self->{'replaced'} =
$self->replace_placeholders(["mkfifo \257<\257>; (",
$cmdstring,
") & _PID=\$!; cat > \257<\257>; ",
"wait \$_PID; _EXIT=\$?; ",
"rm \257<\257>; exit \$_EXIT"],
0,0);
} else {
$self->{'replaced'} = $cmdstring;
}
if($self->{'replaced'} =~ /^\s*(-\S+)/) {
# Is this really a command in $PATH starting with '-'?
my $cmd = $1;
if(not ::which($cmd)) {
::error("Command ($cmd) starts with '-'. Is this a wrong option?\n");
::wait_and_exit(255);
}
}
if($opt::nice) {
# Prepend \nice -n19 $SHELL -c
# and quote
# \ before nice is needed to avoid tcsh's built-in
$self->{'replaced'} = '\nice'. " -n". $opt::nice. " ".
$Global::shell. " -c ".
::shell_quote_scalar($self->{'replaced'});
}
if($opt::shellquote) {
# Prepend echo
# and quote twice
$self->{'replaced'} = "echo " .
::shell_quote_scalar(::shell_quote_scalar($self->{'replaced'}));
} }
} }
return $self->{'replaced'}; return $self->{'replaced'};
@ -6761,6 +6775,15 @@ sub new {
my @unget = (); my @unget = ();
my ($count,%replacecount,$posrpl,$perlexpr,%len); my ($count,%replacecount,$posrpl,$perlexpr,%len);
my @command = @$commandref; my @command = @$commandref;
# If the first command start with '-' it is probably an option
if($command[0] =~ /^\s*(-\S+)/) {
# Is this really a command in $PATH starting with '-'?
my $cmd = $1;
if(not ::which($cmd)) {
::error("Command ($cmd) starts with '-'. Is this a wrong option?\n");
::wait_and_exit(255);
}
}
# Replace replacement strings with {= perl expr =} # Replace replacement strings with {= perl expr =}
# Protect matching inside {= perl expr =} # Protect matching inside {= perl expr =}
# by replacing {= and =} with \257< and \257> # by replacing {= and =} with \257< and \257>

View file

@ -160,7 +160,7 @@ B<--basenameextensionreplace>.
To understand replacement strings see B<{}>. To understand replacement strings see B<{}>.
=item B<{#}> (alpha testing) =item B<{#}> (beta testing)
Sequence number of the job to run. This replacement string will be Sequence number of the job to run. This replacement string will be
replaced by the sequence number of the job being run. It contains the replaced by the sequence number of the job being run. It contains the
@ -171,7 +171,7 @@ The replacement string B<{#}> can be changed with B<--seqreplace>.
To understand replacement strings see B<{}>. To understand replacement strings see B<{}>.
=item B<{%}> (alpha testing) =item B<{%}> (beta testing)
Job slot number. This replacement string will be replaced by the job's Job slot number. This replacement string will be replaced by the job's
slot number between 1 and number of jobs to run in parallel. There slot number between 1 and number of jobs to run in parallel. There
@ -556,7 +556,7 @@ If I<eof-str> is omitted, there is no end of file string. If neither
B<-E> nor B<-e> is used, no end of file string is used. B<-E> nor B<-e> is used, no end of file string is used.
=item B<--env> I<var> (alpha testing) =item B<--env> I<var> (beta testing)
Copy environment variable I<var>. This will copy I<var> to the Copy environment variable I<var>. This will copy I<var> to the
environment that the command is run in. This is especially useful for environment that the command is run in. This is especially useful for
@ -937,7 +937,7 @@ This is useful for scripts that depend on features only available from
a certain version of GNU B<parallel>. a certain version of GNU B<parallel>.
=item B<--nonall> (beta testing) =item B<--nonall>
B<--onall> with no arguments. Run the command on all computers given B<--onall> with no arguments. Run the command on all computers given
with B<--sshlogin> but take no arguments. GNU B<parallel> will log with B<--sshlogin> but take no arguments. GNU B<parallel> will log
@ -948,7 +948,7 @@ This is useful for running the same command (e.g. uptime) on a list of
servers. servers.
=item B<--onall> (beta testing) =item B<--onall>
Run all the jobs on all computers given with B<--sshlogin>. GNU Run all the jobs on all computers given with B<--sshlogin>. GNU
B<parallel> will log into B<--jobs> number of computers in parallel B<parallel> will log into B<--jobs> number of computers in parallel
@ -999,7 +999,7 @@ B<--files> is often used with B<--pipe>.
See also: B<--recstart>, B<--recend>, B<--fifo>, B<--cat>, B<--pipepart>. See also: B<--recstart>, B<--recend>, B<--fifo>, B<--cat>, B<--pipepart>.
=item B<--pipepart> (beta testing) =item B<--pipepart>
Pipe parts of a physical file. B<--pipepart> works similar to Pipe parts of a physical file. B<--pipepart> works similar to
B<--pipe>, but is much faster. It has a few limitations: B<--pipe>, but is much faster. It has a few limitations:
@ -1587,9 +1587,9 @@ B<--sshlogin> is often used with B<--transfer>, B<--return>,
B<--cleanup>, and B<--trc>. B<--cleanup>, and B<--trc>.
=item B<--sshloginfile> I<filename> (beta testing) =item B<--sshloginfile> I<filename>
=item B<--slf> I<filename> (beta testing) =item B<--slf> I<filename>
File with sshlogins. The file consists of sshlogins on separate File with sshlogins. The file consists of sshlogins on separate
lines. Empty lines and lines starting with '#' are ignored. Example: lines. Empty lines and lines starting with '#' are ignored. Example:
@ -3198,7 +3198,7 @@ by: B<kill -TERM $PARALLEL_PID>. This only works on the local
computer. computer.
=item $PARALLEL_SHELL (alpha testing) =item $PARALLEL_SHELL (beta testing)
Use this shell the shell for the commands run by GNU Parallel: Use this shell the shell for the commands run by GNU Parallel:

View file

@ -566,7 +566,7 @@ $Global::Initfile && unlink $Global::Initfile;
exit ($err); exit ($err);
sub parse_options { sub parse_options {
$Global::version = 20141022; $Global::version = 20141023;
$Global::progname = 'sql'; $Global::progname = 'sql';
# This must be done first as this may exec myself # This must be done first as this may exec myself

View file

@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
echo '### Test -k' echo '### Test -k'
ulimit -n 50 ulimit -n 70
(echo "sleep 3; echo begin"; seq 1 30 | parallel -kq echo "sleep 1; echo {}"; echo "echo end") \ (echo "sleep 3; echo begin"; seq 1 30 | parallel -kq echo "sleep 1; echo {}"; echo "echo end") \
| stdout parallel -k -j0 | stdout parallel -k -j0

View file

@ -1,6 +1,9 @@
### Tests from xargs ### Tests from xargs
parallel: Warning: Only enough file handles to run 248 jobs in parallel.
Running 'parallel -j0 -N248 --pipe parallel -j0' or raising ulimit -n or /etc/security/limits.conf may help.
echo '### -0 -n3 echo < files0.xi' echo '### -0 -n3 echo < files0.xi'
### -0 -n3 echo < files0.xi ### -0 -n3 echo < files0.xi
parallel: Warning: No more file handles. Raising ulimit -n or /etc/security/limits.conf may help.
stdout xargs -0 -n3 echo < files0.xi stdout xargs -0 -n3 echo < files0.xi
/src/gnu/autoconf-1.11 /src/gnu/autoconf-1.11/README /src/gnu/autoconf-1.11/Makefile.in /src/gnu/autoconf-1.11 /src/gnu/autoconf-1.11/README /src/gnu/autoconf-1.11/Makefile.in
/src/gnu/autoconf-1.11/INSTALL /src/gnu/autoconf-1.11/NEWS /src/gnu/autoconf-1.11/COPYING /src/gnu/autoconf-1.11/INSTALL /src/gnu/autoconf-1.11/NEWS /src/gnu/autoconf-1.11/COPYING

View file

@ -77,35 +77,35 @@ OK
Input for ssh Input for ssh
parallel@parallel-server1 mkdir -p ./. parallel@parallel-server1 mkdir -p ./.
-l parallel parallel-server1 rsync --server -lDrRze.iLsfx . ./. -l parallel parallel-server1 rsync --server -lDrRze.iLsfx . ./.
-tt -oLogLevel=quiet parallel@parallel-server1 eval `echo $SHELL | grep "/t\{0,1\}csh" > /dev/null && echo setenv PARALLEL_SEQ 2\; setenv PARALLEL_PID 00000 || echo PARALLEL_SEQ=2\;export PARALLEL_SEQ\; PARALLEL_PID=00000\;export PARALLEL_PID` ; tty >/dev/null && stty isig -onlcr -echo;cat tmp/parallel.file.' -tt -oLogLevel=quiet parallel@parallel-server1 eval `echo $SHELL | grep "/t\{0,1\}csh" > /dev/null && echo setenv PARALLEL_SEQ 1\; setenv PARALLEL_PID 00000 || echo PARALLEL_SEQ=1\;export PARALLEL_SEQ\; PARALLEL_PID=00000\;export PARALLEL_PID` ; tty >/dev/null && stty isig -onlcr -echo;cat tmp/parallel.file.'
'newline2 > tmp/parallel.file.'
'newline2.out;cat tmp/parallel.file.'
'newline2 > tmp/parallel.file.'
'newline2.out2
-l parallel parallel-server1 cd ././tmp; rsync --server --sender -lDrRze.iLsfx . ./parallel.file.'
'newline2.out
-l parallel parallel-server1 cd ././tmp; rsync --server --sender -lDrRze.iLsfx . ./parallel.file.'
'newline2.out2
parallel@parallel-server1 (rm -f ./tmp/parallel.file.'
'newline2; rmdir ./tmp/ ./ 2>/dev/null;)
parallel@parallel-server1 (rm -f ./tmp/parallel.file.'
'newline2.out; rmdir ./tmp/ ./ 2>/dev/null;)
parallel@parallel-server1 (rm -f ./tmp/parallel.file.'
'newline2.out2; rmdir ./tmp/ ./ 2>/dev/null;)
parallel@parallel-server2 mkdir -p ./.
-l parallel parallel-server2 rsync --server -lDrRze.iLsfx . ./.
-tt -oLogLevel=quiet parallel@parallel-server2 eval `echo $SHELL | grep "/t\{0,1\}csh" > /dev/null && echo setenv PARALLEL_SEQ 1\; setenv PARALLEL_PID 00000 || echo PARALLEL_SEQ=1\;export PARALLEL_SEQ\; PARALLEL_PID=00000\;export PARALLEL_PID` ; tty >/dev/null && stty isig -onlcr -echo;cat tmp/parallel.file.'
'newline1 > tmp/parallel.file.' 'newline1 > tmp/parallel.file.'
'newline1.out;cat tmp/parallel.file.' 'newline1.out;cat tmp/parallel.file.'
'newline1 > tmp/parallel.file.' 'newline1 > tmp/parallel.file.'
'newline1.out2 'newline1.out2
-l parallel parallel-server2 cd ././tmp; rsync --server --sender -lDrRze.iLsfx . ./parallel.file.' -l parallel parallel-server1 cd ././tmp; rsync --server --sender -lDrRze.iLsfx . ./parallel.file.'
'newline1.out 'newline1.out
-l parallel parallel-server2 cd ././tmp; rsync --server --sender -lDrRze.iLsfx . ./parallel.file.' -l parallel parallel-server1 cd ././tmp; rsync --server --sender -lDrRze.iLsfx . ./parallel.file.'
'newline1.out2 'newline1.out2
parallel@parallel-server2 (rm -f ./tmp/parallel.file.' parallel@parallel-server1 (rm -f ./tmp/parallel.file.'
'newline1; rmdir ./tmp/ ./ 2>/dev/null;) 'newline1; rmdir ./tmp/ ./ 2>/dev/null;)
parallel@parallel-server2 (rm -f ./tmp/parallel.file.' parallel@parallel-server1 (rm -f ./tmp/parallel.file.'
'newline1.out; rmdir ./tmp/ ./ 2>/dev/null;) 'newline1.out; rmdir ./tmp/ ./ 2>/dev/null;)
parallel@parallel-server2 (rm -f ./tmp/parallel.file.' parallel@parallel-server1 (rm -f ./tmp/parallel.file.'
'newline1.out2; rmdir ./tmp/ ./ 2>/dev/null;) 'newline1.out2; rmdir ./tmp/ ./ 2>/dev/null;)
parallel@parallel-server2 mkdir -p ./.
-l parallel parallel-server2 rsync --server -lDrRze.iLsfx . ./.
-tt -oLogLevel=quiet parallel@parallel-server2 eval `echo $SHELL | grep "/t\{0,1\}csh" > /dev/null && echo setenv PARALLEL_SEQ 2\; setenv PARALLEL_PID 00000 || echo PARALLEL_SEQ=2\;export PARALLEL_SEQ\; PARALLEL_PID=00000\;export PARALLEL_PID` ; tty >/dev/null && stty isig -onlcr -echo;cat tmp/parallel.file.'
'newline2 > tmp/parallel.file.'
'newline2.out;cat tmp/parallel.file.'
'newline2 > tmp/parallel.file.'
'newline2.out2
-l parallel parallel-server2 cd ././tmp; rsync --server --sender -lDrRze.iLsfx . ./parallel.file.'
'newline2.out
-l parallel parallel-server2 cd ././tmp; rsync --server --sender -lDrRze.iLsfx . ./parallel.file.'
'newline2.out2
parallel@parallel-server2 (rm -f ./tmp/parallel.file.'
'newline2; rmdir ./tmp/ ./ 2>/dev/null;)
parallel@parallel-server2 (rm -f ./tmp/parallel.file.'
'newline2.out; rmdir ./tmp/ ./ 2>/dev/null;)
parallel@parallel-server2 (rm -f ./tmp/parallel.file.'
'newline2.out2; rmdir ./tmp/ ./ 2>/dev/null;)