Fixed bug #50901: --sqlworker should use hostname in the joblog instead of :.

This commit is contained in:
Ole Tange 2017-04-30 19:00:37 +02:00
parent e49dd0d5d0
commit a7a9e522dd
12 changed files with 318 additions and 259 deletions

View file

@ -196,9 +196,9 @@ file:///home/tange/privat/parallel/doc/release_new_version
from:tange@gnu.org from:tange@gnu.org
to:parallel@gnu.org, bug-parallel@gnu.org to:parallel@gnu.org, bug-parallel@gnu.org
Subject: GNU Parallel 20170422 ('Санкт-Петербу́рг') released <<[stable]>> Subject: GNU Parallel 20170522 ('') released <<[stable]>>
GNU Parallel 20170422 ('Санкт-Петербу́рг') <<[stable]>> has been released. It is available for download at: http://ftpmirror.gnu.org/parallel/ GNU Parallel 20170522 ('') <<[stable]>> has been released. It is available for download at: http://ftpmirror.gnu.org/parallel/
<<No new functionality was introduced so this is a good candidate for a stable release.>> <<No new functionality was introduced so this is a good candidate for a stable release.>>
@ -214,22 +214,26 @@ New in this release:
http://meta.askubuntu.com/a/16750/22307 http://meta.askubuntu.com/a/16750/22307
http://meta.serverfault.com/a/9040/45704 http://meta.serverfault.com/a/9040/45704
http://bmcbioinformatics.biomedcentral.com/articles/10.1186/s12859-017-1593-0 http://pubs.rsc.org/-/content/articlelanding/2017/cp/c7cp01662j#!divAbstract
https://128.84.21.199/pdf/1703.09026.pdf ftp://frapftp.fire.ca.gov/outgoing/transfer/PUC_Map1/Utility%20Fire%20map%201%20final%20review%20and%20development%20report21616.pdf
https://wiki.ncsa.illinois.edu/display/ROGER/Using+GNU+Parallel https://arxiv.org/pdf/1704.02257.pdf
https://github.com/lucascbeyeler/zmbackup http://www.sciencedirect.com/science/article/pii/S0044848616312194
http://helpful.knobs-dials.com/index.php/Find_and_xargs_and_parallel#Parallel
https://github.com/mlangill/microbiome_helper/wiki/Quick-Introduction-to-GNU-Parallel https://www.aclweb.org/anthology/E/E17/E17-1050.pdf
http://journals.plos.org/plosone/article?id=10.1371/journal.pone.0174575 http://www.atmos-meas-tech.net/10/1425/2017/amt-10-1425-2017.pdf
https://www.slideshare.net/sharatsc/data-science-at-the-command-line http://amslaurea.unibo.it/12261/1/nurrito_eugenio_tesi_fisica_magistrale.pdf
http://www.jianshu.com/p/67b0665490ac http://biorxiv.org/content/biorxiv/early/2017/04/27/131680.full.pdf
http://www.nature.com/nprot/journal/v12/n5/full/nprot.2017.022.html?WT.feed_name=subjects_biotechnology
* <<Citation needed: https://sdstrowes.co.uk/publications/sdstrowes-rdns-aaaa.pdf>>
* <<Possibly http://link.springer.com/chapter/10.1007%2F978-3-319-22053-6_46>> * <<Possibly http://link.springer.com/chapter/10.1007%2F978-3-319-22053-6_46>>

View file

@ -23,9 +23,6 @@ doc_DATA = parallel.html env_parallel.html sem.html sql.html niceload.html \
parcat.pdf parset.pdf parcat.pdf parset.pdf
endif endif
parset.pod: parset
cp parset parset.pod
# Build documentation file if the tool to build exists. # Build documentation file if the tool to build exists.
# Otherwise: Use the distributed version # Otherwise: Use the distributed version
parallel.1: parallel.pod parallel.1: parallel.pod
@ -77,13 +74,13 @@ niceload.1: niceload.pod
&& mv $(srcdir)/niceload.1n $(srcdir)/niceload.1 \ && mv $(srcdir)/niceload.1n $(srcdir)/niceload.1 \
|| echo "Warning: pod2man not found. Using old niceload.1" || echo "Warning: pod2man not found. Using old niceload.1"
parcat.1: parcat parcat.1: parcat.pod
pod2man --release='$(PACKAGE_VERSION)' --center='$(PACKAGE_NAME)' \ pod2man --release='$(PACKAGE_VERSION)' --center='$(PACKAGE_NAME)' \
--section=1 $(srcdir)/parcat > $(srcdir)/parcat.1n \ --section=1 $(srcdir)/parcat > $(srcdir)/parcat.1n \
&& mv $(srcdir)/parcat.1n $(srcdir)/parcat.1 \ && mv $(srcdir)/parcat.1n $(srcdir)/parcat.1 \
|| echo "Warning: pod2man not found. Using old parcat.1" || echo "Warning: pod2man not found. Using old parcat.1"
parset.1: parset parset.1: parset.pod
pod2man --release='$(PACKAGE_VERSION)' --center='$(PACKAGE_NAME)' \ pod2man --release='$(PACKAGE_VERSION)' --center='$(PACKAGE_NAME)' \
--section=1 $(srcdir)/parset > $(srcdir)/parset.1n \ --section=1 $(srcdir)/parset > $(srcdir)/parset.1n \
&& mv $(srcdir)/parset.1n $(srcdir)/parset.1 \ && mv $(srcdir)/parset.1n $(srcdir)/parset.1 \
@ -194,7 +191,7 @@ parcat.texi: parcat
pod2texi --output=$(srcdir)/parcat.texi $(srcdir)/parcat \ pod2texi --output=$(srcdir)/parcat.texi $(srcdir)/parcat \
|| echo "Warning: pod2texi not found. Using old parcat.texi" || echo "Warning: pod2texi not found. Using old parcat.texi"
parset.texi: parset parset.texi: parset.pod
pod2texi --output=$(srcdir)/parset.texi $(srcdir)/parset \ pod2texi --output=$(srcdir)/parset.texi $(srcdir)/parset \
|| echo "Warning: pod2texi not found. Using old parset.texi" || echo "Warning: pod2texi not found. Using old parset.texi"
@ -234,7 +231,7 @@ parcat.pdf: parcat
pod2pdf --output-file $(srcdir)/parcat.pdf $(srcdir)/parcat --title "GNU parcat" \ pod2pdf --output-file $(srcdir)/parcat.pdf $(srcdir)/parcat --title "GNU parcat" \
|| echo "Warning: pod2pdf not found. Using old parcat.pdf" || echo "Warning: pod2pdf not found. Using old parcat.pdf"
parset.pdf: parset parset.pdf: parset.pod
pod2pdf --output-file $(srcdir)/parset.pdf $(srcdir)/parset --title "GNU parset" \ pod2pdf --output-file $(srcdir)/parset.pdf $(srcdir)/parset --title "GNU parset" \
|| echo "Warning: pod2pdf not found. Using old parset.pdf" || echo "Warning: pod2pdf not found. Using old parset.pdf"
@ -258,6 +255,7 @@ EXTRA_DIST = parallel sem sql niceload parcat parset env_parallel \
env_parallel.ash env_parallel.bash env_parallel.csh \ env_parallel.ash env_parallel.bash env_parallel.csh \
env_parallel.dash env_parallel.fish env_parallel.ksh \ env_parallel.dash env_parallel.fish env_parallel.ksh \
env_parallel.pdksh env_parallel.sh env_parallel.tcsh \ env_parallel.pdksh env_parallel.sh env_parallel.tcsh \
env_parallel.zsh sem.pod parallel.pod env_parallel.pod \ env_parallel.zsh parcat.pod parset.pod sem.pod parallel.pod \
niceload.pod parallel_tutorial.pod parallel_design.pod \ env_parallel.pod niceload.pod parallel_tutorial.pod \
parallel_alternatives.pod $(DISTCLEANFILES) parallel_design.pod parallel_alternatives.pod \
$(DISTCLEANFILES)

View file

@ -266,9 +266,10 @@ EXTRA_DIST = parallel sem sql niceload parcat parset env_parallel \
env_parallel.ash env_parallel.bash env_parallel.csh \ env_parallel.ash env_parallel.bash env_parallel.csh \
env_parallel.dash env_parallel.fish env_parallel.ksh \ env_parallel.dash env_parallel.fish env_parallel.ksh \
env_parallel.pdksh env_parallel.sh env_parallel.tcsh \ env_parallel.pdksh env_parallel.sh env_parallel.tcsh \
env_parallel.zsh sem.pod parallel.pod env_parallel.pod \ env_parallel.zsh parcat.pod parset.pod sem.pod parallel.pod \
niceload.pod parallel_tutorial.pod parallel_design.pod \ env_parallel.pod niceload.pod parallel_tutorial.pod \
parallel_alternatives.pod $(DISTCLEANFILES) parallel_design.pod parallel_alternatives.pod \
$(DISTCLEANFILES)
all: all-am all: all-am
@ -611,9 +612,6 @@ install-exec-hook:
rm $(DESTDIR)$(bindir)/sem || true rm $(DESTDIR)$(bindir)/sem || true
$(LN_S) parallel $(DESTDIR)$(bindir)/sem $(LN_S) parallel $(DESTDIR)$(bindir)/sem
parset.pod: parset
cp parset parset.pod
# Build documentation file if the tool to build exists. # Build documentation file if the tool to build exists.
# Otherwise: Use the distributed version # Otherwise: Use the distributed version
parallel.1: parallel.pod parallel.1: parallel.pod
@ -664,13 +662,13 @@ niceload.1: niceload.pod
&& mv $(srcdir)/niceload.1n $(srcdir)/niceload.1 \ && mv $(srcdir)/niceload.1n $(srcdir)/niceload.1 \
|| echo "Warning: pod2man not found. Using old niceload.1" || echo "Warning: pod2man not found. Using old niceload.1"
parcat.1: parcat parcat.1: parcat.pod
pod2man --release='$(PACKAGE_VERSION)' --center='$(PACKAGE_NAME)' \ pod2man --release='$(PACKAGE_VERSION)' --center='$(PACKAGE_NAME)' \
--section=1 $(srcdir)/parcat > $(srcdir)/parcat.1n \ --section=1 $(srcdir)/parcat > $(srcdir)/parcat.1n \
&& mv $(srcdir)/parcat.1n $(srcdir)/parcat.1 \ && mv $(srcdir)/parcat.1n $(srcdir)/parcat.1 \
|| echo "Warning: pod2man not found. Using old parcat.1" || echo "Warning: pod2man not found. Using old parcat.1"
parset.1: parset parset.1: parset.pod
pod2man --release='$(PACKAGE_VERSION)' --center='$(PACKAGE_NAME)' \ pod2man --release='$(PACKAGE_VERSION)' --center='$(PACKAGE_NAME)' \
--section=1 $(srcdir)/parset > $(srcdir)/parset.1n \ --section=1 $(srcdir)/parset > $(srcdir)/parset.1n \
&& mv $(srcdir)/parset.1n $(srcdir)/parset.1 \ && mv $(srcdir)/parset.1n $(srcdir)/parset.1 \
@ -781,7 +779,7 @@ parcat.texi: parcat
pod2texi --output=$(srcdir)/parcat.texi $(srcdir)/parcat \ pod2texi --output=$(srcdir)/parcat.texi $(srcdir)/parcat \
|| echo "Warning: pod2texi not found. Using old parcat.texi" || echo "Warning: pod2texi not found. Using old parcat.texi"
parset.texi: parset parset.texi: parset.pod
pod2texi --output=$(srcdir)/parset.texi $(srcdir)/parset \ pod2texi --output=$(srcdir)/parset.texi $(srcdir)/parset \
|| echo "Warning: pod2texi not found. Using old parset.texi" || echo "Warning: pod2texi not found. Using old parset.texi"
@ -821,7 +819,7 @@ parcat.pdf: parcat
pod2pdf --output-file $(srcdir)/parcat.pdf $(srcdir)/parcat --title "GNU parcat" \ pod2pdf --output-file $(srcdir)/parcat.pdf $(srcdir)/parcat --title "GNU parcat" \
|| echo "Warning: pod2pdf not found. Using old parcat.pdf" || echo "Warning: pod2pdf not found. Using old parcat.pdf"
parset.pdf: parset parset.pdf: parset.pod
pod2pdf --output-file $(srcdir)/parset.pdf $(srcdir)/parset --title "GNU parset" \ pod2pdf --output-file $(srcdir)/parset.pdf $(srcdir)/parset --title "GNU parset" \
|| echo "Warning: pod2pdf not found. Using old parset.pdf" || echo "Warning: pod2pdf not found. Using old parset.pdf"

View file

@ -24,7 +24,7 @@
use strict; use strict;
use Getopt::Long; use Getopt::Long;
$Global::progname="niceload"; $Global::progname="niceload";
$Global::version = 20170422; $Global::version = 20170423;
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) {

View file

@ -266,7 +266,7 @@ sub pipe_tee_setup {
} }
# cat foo | tee t1 t2 t3 t4 t5 > /dev/null # cat foo | tee t1 t2 t3 t4 t5 > /dev/null
if(not fork()){ if(not fork()){
# Let tee inheirit our stdin # Let tee inherit our stdin
# and redirect stdout to null # and redirect stdout to null
open STDOUT, ">","/dev/null"; open STDOUT, ">","/dev/null";
exec "tee",@fifos; exec "tee",@fifos;
@ -300,7 +300,8 @@ sub pipe_part_files {
# Make @cat_prepends # Make @cat_prepends
my @cat_prepends = (); my @cat_prepends = ();
for(my $i=0; $i<$#pos; $i++) { for(my $i=0; $i<$#pos; $i++) {
push @cat_prepends, cat_partial($file, 0, length($header), $pos[$i], $pos[$i+1]); push(@cat_prepends,
cat_partial($file, 0, length($header), $pos[$i], $pos[$i+1]));
} }
return @cat_prepends; return @cat_prepends;
} }
@ -487,7 +488,8 @@ sub spreadstdin {
if($Global::max_number_of_args) { if($Global::max_number_of_args) {
# -N => (start..*?end){n} # -N => (start..*?end){n}
# -L -N => (start..*?end){n*l} # -L -N => (start..*?end){n*l}
my $read_n_lines = $Global::max_number_of_args * ($Global::max_lines || 1); my $read_n_lines =
$Global::max_number_of_args * ($Global::max_lines || 1);
while($buf =~ s/((?:$recstart.*?$recend){$read_n_lines})($recstart.*)$/$2/os) { while($buf =~ s/((?:$recstart.*?$recend){$read_n_lines})($recstart.*)$/$2/os) {
# Copy to modifiable variable # Copy to modifiable variable
my $b = $1; my $b = $1;
@ -510,7 +512,8 @@ sub spreadstdin {
if($Global::max_number_of_args) { if($Global::max_number_of_args) {
# -N => (start..*?end){n} # -N => (start..*?end){n}
my $i = 0; my $i = 0;
my $read_n_lines = $Global::max_number_of_args * ($Global::max_lines || 1); my $read_n_lines =
$Global::max_number_of_args * ($Global::max_lines || 1);
while(($i = nindex(\$buf,$recendrecstart,$read_n_lines)) != -1) { while(($i = nindex(\$buf,$recendrecstart,$read_n_lines)) != -1) {
$i += length $recend; # find the actual splitting location $i += length $recend; # find the actual splitting location
$anything_written += $anything_written +=
@ -547,7 +550,8 @@ sub spreadstdin {
::debug("init", "Done reading input\n"); ::debug("init", "Done reading input\n");
# If there is anything left in the buffer write it # If there is anything left in the buffer write it
write_record_to_pipe($chunk_number++,\$header,\$buf,$recstart,$recend,length $buf); write_record_to_pipe($chunk_number++, \$header, \$buf, $recstart,
$recend, length $buf);
if($opt::retries) { if($opt::retries) {
$Global::no_more_input = 1; $Global::no_more_input = 1;
@ -1099,7 +1103,8 @@ sub parse_options {
if(@opt::v) { $Global::verbose = $#opt::v+1; } # Convert -v -v to v=2 if(@opt::v) { $Global::verbose = $#opt::v+1; } # Convert -v -v to v=2
$Global::debug = $opt::D; $Global::debug = $opt::D;
$Global::shell = $ENV{'PARALLEL_SHELL'} || parent_shell($$) || $ENV{'SHELL'} || "/bin/sh"; $Global::shell = $ENV{'PARALLEL_SHELL'} || parent_shell($$)
|| $ENV{'SHELL'} || "/bin/sh";
$Global::cshell = $Global::shell =~ m:/csh:; $Global::cshell = $Global::shell =~ m:/csh:;
if(defined $opt::X) { $Global::ContextReplace = 1; } if(defined $opt::X) { $Global::ContextReplace = 1; }
if(defined $opt::silent) { $Global::verbose = 0; } if(defined $opt::silent) { $Global::verbose = 0; }
@ -1114,7 +1119,9 @@ sub parse_options {
if(defined $opt::verbose) { $Global::stderr_verbose = 1; } if(defined $opt::verbose) { $Global::stderr_verbose = 1; }
parse_replacement_string_options(); parse_replacement_string_options();
if(defined $opt::eof) { $Global::end_of_file_string = $opt::eof; } if(defined $opt::eof) { $Global::end_of_file_string = $opt::eof; }
if(defined $opt::max_args) { $Global::max_number_of_args = $opt::max_args; } if(defined $opt::max_args) {
$Global::max_number_of_args = $opt::max_args;
}
if(defined $opt::timeout) { if(defined $opt::timeout) {
$Global::timeoutq = TimeoutQueue->new($opt::timeout); $Global::timeoutq = TimeoutQueue->new($opt::timeout);
} }
@ -1363,7 +1370,7 @@ sub check_invalid_option_combinations {
sub init_globals { sub init_globals {
# Defaults: # Defaults:
$Global::version = 20170422; $Global::version = 20170423;
$Global::progname = 'parallel'; $Global::progname = 'parallel';
$Global::infinity = 2**31; $Global::infinity = 2**31;
$Global::debug = 0; $Global::debug = 0;
@ -1852,7 +1859,8 @@ sub read_options {
} }
my $script = shell_quote_scalar(shift @ARGV); my $script = shell_quote_scalar(shift @ARGV);
# exec myself to split $ARGV[0] into separate fields # exec myself to split $ARGV[0] into separate fields
exec "$0 --internal-pipe-means-argfiles @options @parser $script ::: @ARGV"; exec "$0 --internal-pipe-means-argfiles @options @parser $script ".
"::: @ARGV";
} }
} }
if($ARGV[0] =~ / --shebang(-?wrap)? /) { if($ARGV[0] =~ / --shebang(-?wrap)? /) {
@ -1886,7 +1894,8 @@ sub read_options {
} }
for my $profile (@profiles) { for my $profile (@profiles) {
if(-r $profile) { if(-r $profile) {
open (my $in_fh, "<", $profile) || ::die_bug("read-profile: $profile"); open (my $in_fh, "<", $profile) ||
::die_bug("read-profile: $profile");
while(<$in_fh>) { while(<$in_fh>) {
/^\s*\#/ and next; /^\s*\#/ and next;
chomp; chomp;
@ -2138,11 +2147,12 @@ sub shell_quote_scalar {
} }
sub shell_quote_file { sub shell_quote_file {
# Quote the string so shell will not expand any special chars and prepend ./ if needed # Quote the string so shell will not expand any special chars
# and prepend ./ if needed
# Input: # Input:
# $filename = filename to be shell quoted # $filename = filename to be shell quoted
# Returns: # Returns:
# $quoted_filename = filename quoted with \ as needed by the shell and ./ if needed # $quoted_filename = filename quoted with \ and ./ if needed
my $a = shell_quote_scalar(shift); my $a = shell_quote_scalar(shift);
if(defined $a) { if(defined $a) {
if($a =~ m:^/: or $a =~ m:^\./:) { if($a =~ m:^/: or $a =~ m:^\./:) {
@ -2283,9 +2293,12 @@ sub set_fh_blocking {
my $fh = shift; my $fh = shift;
$Global::use{"Fcntl"} ||= eval "use Fcntl qw(:DEFAULT :flock); 1;"; $Global::use{"Fcntl"} ||= eval "use Fcntl qw(:DEFAULT :flock); 1;";
my $flags; my $flags;
fcntl($fh, &F_GETFL, $flags) || die $!; # Get the current flags on the filehandle # Get the current flags on the filehandle
$flags &= ~&O_NONBLOCK; # Remove non-blocking from the flags fcntl($fh, &F_GETFL, $flags) || die $!;
fcntl($fh, &F_SETFL, $flags) || die $!; # Set the flags on the filehandle # Remove non-blocking from the flags
$flags &= ~&O_NONBLOCK;
# Set the flags on the filehandle
fcntl($fh, &F_SETFL, $flags) || die $!;
} }
sub set_fh_non_blocking { sub set_fh_non_blocking {
@ -2297,9 +2310,12 @@ sub set_fh_non_blocking {
my $fh = shift; my $fh = shift;
$Global::use{"Fcntl"} ||= eval "use Fcntl qw(:DEFAULT :flock); 1;"; $Global::use{"Fcntl"} ||= eval "use Fcntl qw(:DEFAULT :flock); 1;";
my $flags; my $flags;
fcntl($fh, &F_GETFL, $flags) || die $!; # Get the current flags on the filehandle # Get the current flags on the filehandle
$flags |= &O_NONBLOCK; # Add non-blocking to the flags fcntl($fh, &F_GETFL, $flags) || die $!;
fcntl($fh, &F_SETFL, $flags) || die $!; # Set the flags on the filehandle # Add non-blocking to the flags
$flags |= &O_NONBLOCK;
# Set the flags on the filehandle
fcntl($fh, &F_SETFL, $flags) || die $!;
} }
@ -7032,7 +7048,8 @@ sub runtime {
# Returns: # Returns:
# Run time in seconds with 3 decimals # Run time in seconds with 3 decimals
my $self = shift; my $self = shift;
return sprintf("%.3f",int(($self->endtime() - $self->starttime())*1000)/1000); return sprintf("%.3f",
int(($self->endtime() - $self->starttime())*1000)/1000);
} }
sub endtime { sub endtime {
@ -7330,9 +7347,15 @@ sub set_sshlogin {
$self->{'sshlogin'} = $sshlogin; $self->{'sshlogin'} = $sshlogin;
delete $self->{'sshlogin_wrap'}; # If sshlogin is changed the wrap is wrong delete $self->{'sshlogin_wrap'}; # If sshlogin is changed the wrap is wrong
delete $self->{'wrapped'}; delete $self->{'wrapped'};
$opt::sqlworker and
$Global::sql->update("SET Host = ? WHERE Seq = ".$self->seq(), if($opt::sqlworker) {
$sshlogin->string()); # Identify worker as --sqlworker often runs on different machines
my $host = $sshlogin->string();
if($host eq ":") {
$host = ::hostname();
}
$Global::sql->update("SET Host = ? WHERE Seq = ".$self->seq(), $host);
}
} }
sub sshlogin { sub sshlogin {
@ -7536,7 +7559,8 @@ sub sshlogin_wrap {
push @vars, grep { not defined $ignore{$_} } keys %ENV; push @vars, grep { not defined $ignore{$_} } keys %ENV;
@vars = grep { not /^_$/ } @vars; @vars = grep { not /^_$/ } @vars;
} else { } else {
::error("Run '$Global::progname --record-env' in a clean environment first."); ::error("Run '$Global::progname --record-env' ".
"in a clean environment first.");
::wait_and_exit(255); ::wait_and_exit(255);
} }
} }
@ -7795,12 +7819,15 @@ sub sshreturn {
$nobasedir =~ s:.*/\./::; $nobasedir =~ s:.*/\./::;
$cd = ::shell_quote_file(::dirname($nobasedir)); $cd = ::shell_quote_file(::dirname($nobasedir));
my $rsync_cd = '--rsync-path='.::shell_quote_scalar("cd $wd$cd; rsync"); my $rsync_cd = '--rsync-path='.::shell_quote_scalar("cd $wd$cd; rsync");
my $basename = ::shell_quote_scalar(::shell_quote_file(::basename($file))); my $basename =
::shell_quote_scalar(::shell_quote_file(::basename($file)));
# --return # --return
# mkdir -p /home/tange/dir/subdir/; # mkdir -p /home/tange/dir/subdir/;
# rsync (--protocol 30) -rlDzR --rsync-path="cd /home/tange/dir/subdir/; rsync" # rsync (--protocol 30) -rlDzR
# --rsync-path="cd /home/tange/dir/subdir/; rsync"
# server:file.gz /home/tange/dir/subdir/ # server:file.gz /home/tange/dir/subdir/
$pre .= "mkdir -p $basedir$cd && ".$sshlogin->rsync()." $rsync_cd $rsync_opt $serverlogin:". $pre .= "mkdir -p $basedir$cd && ". $sshlogin->rsync().
" $rsync_cd $rsync_opt $serverlogin:".
$basename . " ".$basedir.$cd.";"; $basename . " ".$basedir.$cd.";";
} }
return $pre; return $pre;
@ -8998,7 +9025,8 @@ sub populate {
if($opt::sqlmaster) { if($opt::sqlmaster) {
# Insert the V1..Vn for this $seq in SQL table instead of generating one # Insert the V1..Vn for this $seq in SQL table instead of generating one
$Global::sql->insert_records($self->seq(),$self->{'command'},$self->{'arg_list_flat_orig'}); $Global::sql->insert_records($self->seq(), $self->{'command'},
$self->{'arg_list_flat_orig'});
} }
} }
@ -9045,11 +9073,13 @@ sub pop {
if($perlexpr =~ /^(\d+) /) { if($perlexpr =~ /^(\d+) /) {
# Positional # Positional
defined($record->[$1-1]) or next; defined($record->[$1-1]) or next;
$self->{'len'}{$perlexpr} -= length $record->[$1-1]->replace($perlexpr,$quote_arg,$self); $self->{'len'}{$perlexpr} -=
length $record->[$1-1]->replace($perlexpr,$quote_arg,$self);
} else { } else {
for my $arg (@$record) { for my $arg (@$record) {
if(defined $arg) { if(defined $arg) {
$self->{'len'}{$perlexpr} -= length $arg->replace($perlexpr,$quote_arg,$self); $self->{'len'}{$perlexpr} -=
length $arg->replace($perlexpr,$quote_arg,$self);
} }
} }
} }
@ -9321,10 +9351,10 @@ sub replaced {
my $context_replace; my $context_replace;
my $perl_expressions_as_re; my $perl_expressions_as_re;
my @arg; my @arg;
my %words_containing_replacement_strings; my %words_with_rpl_strings;
sub fish_out_words_containing_replacement_strings { sub fish_out_words_with_rpl_strings {
if(not $words_containing_replacement_strings{$context_replace,@target}) { if(not $words_with_rpl_strings{$context_replace,@target}) {
my %word; my %word;
for (@target) { for (@target) {
my $tt = $_; my $tt = $_;
@ -9357,9 +9387,9 @@ sub replaced {
} }
} }
} }
@{$words_containing_replacement_strings{$context_replace,@target}} = keys %word @{$words_with_rpl_strings{$context_replace,@target}} = keys %word
} }
return @{$words_containing_replacement_strings{$context_replace,@target}}; return @{$words_with_rpl_strings{$context_replace,@target}};
} }
sub replace_placeholders { sub replace_placeholders {
@ -9377,7 +9407,7 @@ sub replaced {
my $quote = shift; my $quote = shift;
my $quote_arg = shift; my $quote_arg = shift;
my %replace; my %replace;
# -X = context replace (fish_out_words_containing_replacement_strings) # -X = context replace (fish_out_words_with_rpl_strings)
$context_replace = $self->{'context_replace'}; $context_replace = $self->{'context_replace'};
@target = @$targetref; @target = @$targetref;
::debug("replace", "Replace @target\n"); ::debug("replace", "Replace @target\n");
@ -9404,7 +9434,7 @@ sub replaced {
join("|", map {s/^-?\d+//; "\Q$_\E"} keys %{$self->{'replacecount'}}); join("|", map {s/^-?\d+//; "\Q$_\E"} keys %{$self->{'replacecount'}});
# Fish out the words that have replacement strings in them # Fish out the words that have replacement strings in them
for my $word ( for my $word (
fish_out_words_containing_replacement_strings()) { fish_out_words_with_rpl_strings()) {
# word = AB \257< perlexpr \257> CD \257< perlexpr \257> EF # word = AB \257< perlexpr \257> CD \257< perlexpr \257> EF
::debug("replace", "Replacing in $word\n"); ::debug("replace", "Replacing in $word\n");
my $normal_replace; my $normal_replace;
@ -9505,7 +9535,8 @@ sub new {
$_ or next; $_ or next;
# Disallow \257 to avoid nested {= {= =} =} # Disallow \257 to avoid nested {= {= =} =}
if(/\257/) { if(/\257/) {
::error("Command cannot contain the character \257. Use a function for that."); ::error("Command cannot contain the character \257. ".
"Use a function for that.");
::wait_and_exit(255); ::wait_and_exit(255);
} }
# Needs to match rightmost left parens (Perl defaults to leftmost) # Needs to match rightmost left parens (Perl defaults to leftmost)
@ -9525,7 +9556,8 @@ sub new {
# #
# Replace $$1 in {= perl expr =} with groupings in short hand string # Replace $$1 in {= perl expr =} with groupings in short hand string
# #
# ppar --rpl '{/(\.\S+)/(\.\S+)} s/$$1/$$2/g;' echo {/.tar/.gz} ::: UU.tar.gz # --rpl '{/(\.\S+)/(\.\S+)} s/$$1/$$2/g;'
# echo {/.tar/.gz} ::: UU.tar.gz
my ($prefix,$grp_regexp,$postfix) = my ($prefix,$grp_regexp,$postfix) =
$rpl =~ /^( [^(]* ) # Prefix - e.g. {%% $rpl =~ /^( [^(]* ) # Prefix - e.g. {%%
( \(.*\) )? # Group capture regexp - e.g (.*) ( \(.*\) )? # Group capture regexp - e.g (.*)
@ -9533,7 +9565,8 @@ sub new {
/x; /x;
$grp_regexp ||= ''; $grp_regexp ||= '';
my $rplval = $Global::rpl{$rpl}; my $rplval = $Global::rpl{$rpl};
while(s{( (?: ^|\257> ) [^\257]*? ) # Don't replace after \257 unless \257> while(s{( (?: ^|\257> ) [^\257]*? )
# Don't replace after \257 unless \257>
\Q$prefix\E $grp_regexp \Q$postfix\E} \Q$prefix\E $grp_regexp \Q$postfix\E}
{ {
# The start remains the same # The start remains the same
@ -9876,7 +9909,7 @@ sub real_max_length {
# Find the max_length of a command line # Find the max_length of a command line
# Returns: # Returns:
# The maximal command line length # The maximal command line length
# Use an upper bound of 8 MB if the shell allows for for infinite long lengths # Use an upper bound of 8 MB if the shell allows for infinite long lengths
my $upper = 8_000_000; my $upper = 8_000_000;
my $len = 8; my $len = 8;
do { do {
@ -9938,7 +9971,8 @@ sub tmux_length {
my @out; my @out;
for my $l (1, 2020, 16320, 100000, $len) { for my $l (1, 2020, 16320, 100000, $len) {
my $tmpfile = ::tmpname("tms"); my $tmpfile = ::tmpname("tms");
my $tmuxcmd = $ENV{'PARALLEL_TMUX'}." -S $tmpfile new-session -d -n echo $l". my $tmuxcmd = $ENV{'PARALLEL_TMUX'}.
" -S $tmpfile new-session -d -n echo $l".
("x"x$l). " && echo $l; rm -f $tmpfile"; ("x"x$l). " && echo $l; rm -f $tmpfile";
push @out, ::qqx($tmuxcmd); push @out, ::qqx($tmuxcmd);
::rm($tmpfile); ::rm($tmpfile);
@ -10093,7 +10127,8 @@ sub unget {
sub empty { sub empty {
my $self = shift; my $self = shift;
my $empty = (not @{$self->{'unget'}} and $self->{'arg_sub_queue'}->empty()); my $empty = (not @{$self->{'unget'}} and
$self->{'arg_sub_queue'}->empty());
::debug("run", "RecordColQueue->empty $empty"); ::debug("run", "RecordColQueue->empty $empty");
return $empty; return $empty;
} }
@ -10273,7 +10308,8 @@ sub nest_get {
# Is input source --link'ed to the next? # Is input source --link'ed to the next?
$opt::linkinputsource[$fhn+1]); $opt::linkinputsource[$fhn+1]);
} }
$combarg[2*$fhno] = [$len,$len]; # Find only combinations with this new entry # Find only combinations with this new entry
$combarg[2*$fhno] = [$len,$len];
# map combinations # map combinations
# [ 1, 3, 7 ], [ 2, 4, 1 ] # [ 1, 3, 7 ], [ 2, 4, 1 ]
# => # =>
@ -10695,8 +10731,12 @@ sub get_alias {
"$ENV{HOME}/.dburl.aliases", "/etc/sql/aliases", "$ENV{HOME}/.dburl.aliases", "/etc/sql/aliases",
"$path/dburl.aliases", "$path/dburl.aliases.dist"); "$path/dburl.aliases", "$path/dburl.aliases.dist");
for my $alias_file (@search) { for my $alias_file (@search) {
# local $/ needed if -0 set
local $/ = "\n";
if(-r $alias_file) { if(-r $alias_file) {
push @urlalias, `cat "$alias_file"`; open(my $in, "<", $alias_file) || die;
push @urlalias, <$in>;
close $in;
} }
} }
my ($alias_part,$rest) = $alias=~/(:\w*)(.*)/; my ($alias_part,$rest) = $alias=~/(:\w*)(.*)/;
@ -10743,7 +10783,7 @@ sub check_permissions {
sub parse_dburl { sub parse_dburl {
my $url = shift; my $url = shift;
my %options = (); my %options = ();
# sql:mysql://[[user][:password]@][host][:port]/[database[/table][?sql query]] # sql:mysql://[[user][:password]@][host][:port]/[database[/table][?query]]
if($url=~m!(?:sql:)? # You can prefix with 'sql:' if($url=~m!(?:sql:)? # You can prefix with 'sql:'
((?:oracle|ora|mysql|pg|postgres|postgresql)(?:s|ssl|)| ((?:oracle|ora|mysql|pg|postgres|postgresql)(?:s|ssl|)|
@ -10781,11 +10821,11 @@ sub parse_dburl {
$options{table} = ::undef_if_empty(uri_unescape($7)); $options{table} = ::undef_if_empty(uri_unescape($7));
$options{query} = ::undef_if_empty(uri_unescape($8)); $options{query} = ::undef_if_empty(uri_unescape($8));
::debug("sql", "dburl $url\n"); ::debug("sql", "dburl $url\n");
::debug("sql","databasedriver ",$options{databasedriver}, " user ", $options{user}, ::debug("sql", "databasedriver ", $options{databasedriver},
" user ", $options{user},
" password ", $options{password}, " host ", $options{host}, " password ", $options{password}, " host ", $options{host},
" port ", $options{port}, " database ", $options{database}, " port ", $options{port}, " database ", $options{database},
" table ", $options{table}, " query ", $options{query}, "\n"); " table ", $options{table}, " query ", $options{query}, "\n");
} else { } else {
::error("$url is not a valid DBURL"); ::error("$url is not a valid DBURL");
exit 255; exit 255;
@ -10904,7 +10944,8 @@ sub output {
my $self = shift; my $self = shift;
my $commandline = shift; my $commandline = shift;
$self->update("SET Stdout = ?, Stderr = ? WHERE Seq = ".$commandline->seq(), $self->update("SET Stdout = ?, Stderr = ? WHERE Seq = ".
$commandline->seq(),
join("",@{$commandline->{'output'}{1}}), join("",@{$commandline->{'output'}{1}}),
join("",@{$commandline->{'output'}{2}})); join("",@{$commandline->{'output'}{2}}));
} }
@ -11037,7 +11078,8 @@ sub finished {
my $self = shift; my $self = shift;
if($opt::wait or $Global::start_sqlworker) { if($opt::wait or $Global::start_sqlworker) {
my $table = $self->table(); my $table = $self->table();
my $rv = $self->get("select Seq,Exitval from $table where Exitval <= -1000 limit 1"); my $rv = $self->get("select Seq,Exitval from $table ".
"where Exitval <= -1000 limit 1");
return not $rv->[0]; return not $rv->[0];
} else { } else {
return 1; return 1;
@ -11251,7 +11293,8 @@ sub lock {
} }
} else { } else {
if($total_sleep/1000 > 30) { if($total_sleep/1000 > 30) {
::warning("Semaphore stuck for 30 seconds. Consider using --semaphoretimeout."); ::warning("Semaphore stuck for 30 seconds. ".
"Consider using --semaphoretimeout.");
} }
} }
} }

View file

@ -341,7 +341,7 @@ B<:::> and B<::::> can be mixed. So these are equivalent:
::: 1 2 3 ::: 1 2 3
=item B<:::+> I<arguments> =item B<:::+> I<arguments> (alpha testing)
Like B<:::> but linked like B<--link> to the previous input source. Like B<:::> but linked like B<--link> to the previous input source.
@ -362,7 +362,7 @@ B<:::> and B<::::> can be mixed.
See B<-a>, B<:::> and B<--link>. See B<-a>, B<:::> and B<--link>.
=item B<::::+> I<argfiles> =item B<::::+> I<argfiles> (alpha testing)
Like B<::::> but linked like B<--link> to the previous input source. Like B<::::> but linked like B<--link> to the previous input source.
@ -418,7 +418,7 @@ string that is not in the command line.
See also: B<:::>. See also: B<:::>.
=item B<--bar> =item B<--bar> (alpha testing)
Show progress as a progress bar. In the bar is shown: % of jobs Show progress as a progress bar. In the bar is shown: % of jobs
completed, estimated seconds left, and number of jobs started. completed, estimated seconds left, and number of jobs started.
@ -656,7 +656,7 @@ variables, arrays, and functions) use B<env_parallel>.
See also: B<--record-env>. See also: B<--record-env>.
=item B<--eta> =item B<--eta> (alpha testing)
Show the estimated number of seconds before finishing. This forces GNU Show the estimated number of seconds before finishing. This forces GNU
B<parallel> to read all jobs before starting to find the number of B<parallel> to read all jobs before starting to find the number of
@ -744,9 +744,9 @@ See also: B<--line-buffer> B<--ungroup>
Print a summary of the options to GNU B<parallel> and exit. Print a summary of the options to GNU B<parallel> and exit.
=item B<--halt-on-error> I<val> =item B<--halt-on-error> I<val> (alpha testing)
=item B<--halt> I<val> =item B<--halt> I<val> (alpha testing)
When should GNU B<parallel> terminate? In some situations it makes no When should GNU B<parallel> terminate? In some situations it makes no
sense to run all jobs. GNU B<parallel> should simply give up as soon sense to run all jobs. GNU B<parallel> should simply give up as soon
@ -891,7 +891,7 @@ specified, and for B<-I {}> otherwise. This option is deprecated;
use B<-I> instead. use B<-I> instead.
=item B<--joblog> I<logfile> =item B<--joblog> I<logfile> (alpha testing)
Logfile for executed jobs. Save a list of the executed jobs to Logfile for executed jobs. Save a list of the executed jobs to
I<logfile> in the following TAB separated format: sequence number, I<logfile> in the following TAB separated format: sequence number,
@ -1076,7 +1076,7 @@ Arguments will be recycled if one input source has more arguments than the other
See also B<--header>, B<:::+>, B<::::+>. See also B<--header>, B<:::+>, B<::::+>.
=item B<--load> I<max-load> =item B<--load> I<max-load> (alpha testing)
Do not start new jobs on a given computer unless the number of running Do not start new jobs on a given computer unless the number of running
processes on the computer is less than I<max-load>. I<max-load> uses processes on the computer is less than I<max-load>. I<max-load> uses
@ -1254,7 +1254,7 @@ control on the command line (used by GNU B<parallel> internally when
called with B<--sshlogin>). called with B<--sshlogin>).
=item B<--plus> (alpha testing) =item B<--plus> (beta testing)
Activate additional replacement strings: {+/} {+.} {+..} {+...} {..} Activate additional replacement strings: {+/} {+.} {+..} {+...} {..}
{...} {/..} {/...} {##}. The idea being that '{+foo}' matches the opposite of {...} {/..} {/...} {##}. The idea being that '{+foo}' matches the opposite of
@ -2061,6 +2061,9 @@ should be the same as given by B<--sqlmaster>.
If you have more than one B<--sqlworker> jobs may be run more than If you have more than one B<--sqlworker> jobs may be run more than
once. once.
If B<--sqlworker> runs on the local machine, the hostname in the SQL
table will not be ':' but instead the hostname of the machine.
=item B<--ssh> I<sshcommand> =item B<--ssh> I<sshcommand>
@ -2233,7 +2236,7 @@ B<{}>.
B<--tagstring> is ignored when using B<-u>, B<--onall>, and B<--nonall>. B<--tagstring> is ignored when using B<-u>, B<--onall>, and B<--nonall>.
=item B<--tee> (alpha testing) =item B<--tee> (beta testing)
Pipe all data to all jobs. Used with B<--pipe>/B<--pipepart> and Pipe all data to all jobs. Used with B<--pipe>/B<--pipepart> and
B<:::>. B<:::>.
@ -2274,13 +2277,13 @@ different dir for the files. Setting B<--tmpdir> is equivalent to
setting $TMPDIR. setting $TMPDIR.
=item B<--tmux> =item B<--tmux> (alpha testing)
Use B<tmux> for output. Start a B<tmux> session and run each job in a Use B<tmux> for output. Start a B<tmux> session and run each job in a
window in that session. No other output will be produced. window in that session. No other output will be produced.
=item B<--tmuxpane> =item B<--tmuxpane> (alpha testing)
Use B<tmux> for output but put output into panes in the first window. Use B<tmux> for output but put output into panes in the first window.
Useful if you want to monitor the progress of less than 100 concurrent Useful if you want to monitor the progress of less than 100 concurrent

View file

@ -1,156 +1,5 @@
#!/usr/bin/perl #!/usr/bin/perl
=head1 NAME
parcat - cat files or fifos in parallel
=head1 SYNOPSIS
B<parcat> file(s)
=head1 DESCRIPTION
GNU B<parcat> reads files or fifos in parallel. It writes full lines
so there will be no problem with mixed-half-lines which you risk if
you use:
(cat file1 & cat file2 &) | ...
=head1 EXAMPLES
=head2 Do be done
mkfifo slot-{1..5}-digit-{0..9}
parallel -j5 'seq 100000 | grep {} > slot-{%}-digit-{}' ::: {0..9} &
parallel parcat slot-{1..5}-digit-{} '>' digit-{} ::: {0..9}
=head1 REPORTING BUGS
GNU B<parcat> is part of GNU B<parallel>. Report bugs to <bug-parallel@gnu.org>.
=head1 AUTHOR
Copyright (C) 2016,2017 Ole Tange, http://ole.tange.dk and Free
Software Foundation, Inc.
=head1 LICENSE
Copyright (C) 2007,2008,2009,2010,2011 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
at your option any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
=head2 Documentation license I
Permission is granted to copy, distribute and/or modify this documentation
under the terms of the GNU Free Documentation License, Version 1.3 or
any later version published by the Free Software Foundation; with no
Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
Texts. A copy of the license is included in the file fdl.txt.
=head2 Documentation license II
You are free:
=over 9
=item B<to Share>
to copy, distribute and transmit the work
=item B<to Remix>
to adapt the work
=back
Under the following conditions:
=over 9
=item B<Attribution>
You must attribute the work in the manner specified by the author or
licensor (but not in any way that suggests that they endorse you or
your use of the work).
=item B<Share Alike>
If you alter, transform, or build upon this work, you may distribute
the resulting work only under the same, similar or a compatible
license.
=back
With the understanding that:
=over 9
=item B<Waiver>
Any of the above conditions can be waived if you get permission from
the copyright holder.
=item B<Public Domain>
Where the work or any of its elements is in the public domain under
applicable law, that status is in no way affected by the license.
=item B<Other Rights>
In no way are any of the following rights affected by the license:
=over 9
=item *
Your fair dealing or fair use rights, or other applicable
copyright exceptions and limitations;
=item *
The author's moral rights;
=item *
Rights other persons may have either in the work itself or in
how the work is used, such as publicity or privacy rights.
=back
=item B<Notice>
For any reuse or distribution, you must make clear to others the
license terms of this work.
=back
A copy of the full license is included in the file as cc-by-sa.txt.
=head1 DEPENDENCIES
GNU B<parcat> uses Perl.
=head1 SEE ALSO
B<cat>(1), B<parallel>(1)
=cut
use Symbol qw(gensym); use Symbol qw(gensym);
use IPC::Open3; use IPC::Open3;
use POSIX qw(:errno_h); use POSIX qw(:errno_h);

151
src/parcat.pod Normal file
View file

@ -0,0 +1,151 @@
#!/usr/bin/perl
=head1 NAME
parcat - cat files or fifos in parallel
=head1 SYNOPSIS
B<parcat> file(s)
=head1 DESCRIPTION
GNU B<parcat> reads files or fifos in parallel. It writes full lines
so there will be no problem with mixed-half-lines which you risk if
you use:
(cat file1 & cat file2 &) | ...
=head1 EXAMPLES
=head2 Do be done
mkfifo slot-{1..5}-digit-{0..9}
parallel -j5 'seq 100000 | grep {} > slot-{%}-digit-{}' ::: {0..9} &
parallel parcat slot-{1..5}-digit-{} '>' digit-{} ::: {0..9}
=head1 REPORTING BUGS
GNU B<parcat> is part of GNU B<parallel>. Report bugs to <bug-parallel@gnu.org>.
=head1 AUTHOR
Copyright (C) 2016,2017 Ole Tange, http://ole.tange.dk and Free
Software Foundation, Inc.
=head1 LICENSE
Copyright (C) 2007,2008,2009,2010,2011 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
at your option any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
=head2 Documentation license I
Permission is granted to copy, distribute and/or modify this documentation
under the terms of the GNU Free Documentation License, Version 1.3 or
any later version published by the Free Software Foundation; with no
Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
Texts. A copy of the license is included in the file fdl.txt.
=head2 Documentation license II
You are free:
=over 9
=item B<to Share>
to copy, distribute and transmit the work
=item B<to Remix>
to adapt the work
=back
Under the following conditions:
=over 9
=item B<Attribution>
You must attribute the work in the manner specified by the author or
licensor (but not in any way that suggests that they endorse you or
your use of the work).
=item B<Share Alike>
If you alter, transform, or build upon this work, you may distribute
the resulting work only under the same, similar or a compatible
license.
=back
With the understanding that:
=over 9
=item B<Waiver>
Any of the above conditions can be waived if you get permission from
the copyright holder.
=item B<Public Domain>
Where the work or any of its elements is in the public domain under
applicable law, that status is in no way affected by the license.
=item B<Other Rights>
In no way are any of the following rights affected by the license:
=over 9
=item *
Your fair dealing or fair use rights, or other applicable
copyright exceptions and limitations;
=item *
The author's moral rights;
=item *
Rights other persons may have either in the work itself or in
how the work is used, such as publicity or privacy rights.
=back
=item B<Notice>
For any reuse or distribution, you must make clear to others the
license terms of this work.
=back
A copy of the full license is included in the file as cc-by-sa.txt.
=head1 DEPENDENCIES
GNU B<parcat> uses Perl.
=head1 SEE ALSO
B<cat>(1), B<parallel>(1)
=cut

View file

@ -25,6 +25,8 @@ the destination variable and made to an array.
If I<variablename> contains multiple names separated by ',' or space, If I<variablename> contains multiple names separated by ',' or space,
the names will be the destination variables. the names will be the destination variables.
B<parset> is not production ready and alpha quality.
=head1 OPTIONS =head1 OPTIONS
@ -102,9 +104,6 @@ Copyright (C) 2008,2009,2010 Ole Tange, http://ole.tange.dk
Copyright (C) 2010,2011,2012,2013,2014,2015,2016,2017 Ole Tange, Copyright (C) 2010,2011,2012,2013,2014,2015,2016,2017 Ole Tange,
http://ole.tange.dk and Free Software Foundation, Inc. http://ole.tange.dk and Free Software Foundation, Inc.
Parts of the manual concerning B<xargs> compatibility is inspired by
the manual of B<xargs> from GNU findutils 4.4.2.
=head1 LICENSE =head1 LICENSE
@ -223,9 +222,7 @@ B<parset> uses GNU B<parallel>.
=head1 SEE ALSO =head1 SEE ALSO
B<parallel>(1), B<env_parallel>(1), B<parallel>(1), B<env_parallel>(1), B<bash>(1).
B<bash>(1).
=cut =cut

View file

@ -576,7 +576,7 @@ $Global::Initfile && unlink $Global::Initfile;
exit ($err); exit ($err);
sub parse_options { sub parse_options {
$Global::version = 20170422; $Global::version = 20170423;
$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

@ -233,6 +233,14 @@ line2"' 'echo "command2"'
} }
par_sqlworker_hostname() {
echo 'bug #50901: --sqlworker should use hostname in the joblog instead of :'
parallel --sqlmaster :my/hostname echo ::: 1 2 3
parallel -k --sqlworker :my/hostname
sql :my 'select host from hostname;'
}
export -f $(compgen -A function | grep par_) export -f $(compgen -A function | grep par_)
compgen -A function | grep par_ | sort | compgen -A function | grep par_ | sort |
parallel -j6 --tag -k --joblog +/tmp/jl-`basename $0` '{} 2>&1' parallel -j6 --tag -k --joblog +/tmp/jl-`basename $0` '{} 2>&1'

View file

@ -743,3 +743,11 @@ par_result_replace /tmp/par__49983-baz C
par_result_replace /tmp/par__49983-baz C/seq par_result_replace /tmp/par__49983-baz C/seq
par_result_replace /tmp/par__49983-baz C/stderr par_result_replace /tmp/par__49983-baz C/stderr
par_result_replace /tmp/par__49983-baz C/stdout par_result_replace /tmp/par__49983-baz C/stdout
par_sqlworker_hostname bug #50901: --sqlworker should use hostname in the joblog instead of :
par_sqlworker_hostname 1
par_sqlworker_hostname 2
par_sqlworker_hostname 3
par_sqlworker_hostname host
par_sqlworker_hostname aspire
par_sqlworker_hostname aspire
par_sqlworker_hostname aspire