mirror of
https://git.savannah.gnu.org/git/parallel.git
synced 2024-11-22 14:07:55 +00:00
parallel: sub wrapper implemented. Passed most of the testsuite.
This commit is contained in:
parent
2f9dc0b034
commit
2ff435caea
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
||||||
|
|
221
src/parallel
221
src/parallel
|
@ -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>
|
||||||
|
|
|
@ -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:
|
||||||
|
|
||||||
|
|
2
src/sql
2
src/sql
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;)
|
||||||
|
|
Loading…
Reference in a new issue