mirror of
https://git.savannah.gnu.org/git/parallel.git
synced 2024-11-29 09:27:56 +00:00
parallel: --dryrun implemented. --return of multiple files with
-X. --return of files containing space. Passes testsuite.
This commit is contained in:
parent
3b3c344097
commit
bff9531219
|
@ -1,6 +1,15 @@
|
||||||
--command, -c, --file, and -f now obsoleted. --eta works again.
|
parallel: --dryrun implemented. --return of multiple files with
|
||||||
Bugfix in testsuite for --retries.
|
-X. --return of files containing space.
|
||||||
Lots of dead code removed.
|
|
||||||
|
|
||||||
|
== Bug ==
|
||||||
|
|
||||||
|
--trc {}' 'done
|
||||||
|
|
||||||
|
echo 1' '2 | parallel -vv --trc {}' 'done -S nlv.pi.dk touch {}' 'done
|
||||||
|
|
||||||
|
(echo 1' '2;echo a' 'b) | parallel -qvv --trc {}' 'done -S nlv.pi.dk touch {}' 'done
|
||||||
|
|
||||||
|
|
||||||
== Bug? ==
|
== Bug? ==
|
||||||
|
|
||||||
|
|
|
@ -134,6 +134,9 @@ download at: http://ftp.gnu.org/gnu/parallel/
|
||||||
|
|
||||||
New in this release:
|
New in this release:
|
||||||
|
|
||||||
|
* GNU niceload is now part of GNU Parallel. GNU niceload slows down a
|
||||||
|
program if the load average is above a certain limit.
|
||||||
|
|
||||||
* Implemented --tmpdir to buffer standard output and standard error in
|
* Implemented --tmpdir to buffer standard output and standard error in
|
||||||
a different place.
|
a different place.
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
=head1 NAME
|
=head1 NAME
|
||||||
|
|
||||||
niceload - run a program when the load is below a certain limit
|
niceload - slow down a program when the load average is above a certain limit
|
||||||
|
|
||||||
=head1 SYNOPSIS
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
|
90
src/parallel
90
src/parallel
|
@ -136,6 +136,7 @@ sub get_options_from_array {
|
||||||
"tempdir=s" => \$::opt_tmpdir,
|
"tempdir=s" => \$::opt_tmpdir,
|
||||||
"halt-on-error|H=s" => \$::opt_halt_on_error,
|
"halt-on-error|H=s" => \$::opt_halt_on_error,
|
||||||
"retries=i" => \$::opt_retries,
|
"retries=i" => \$::opt_retries,
|
||||||
|
"dry-run|dryrun" => \$::opt_dryrun,
|
||||||
"progress" => \$::opt_progress,
|
"progress" => \$::opt_progress,
|
||||||
"eta" => \$::opt_eta,
|
"eta" => \$::opt_eta,
|
||||||
"arg-sep|argsep=s" => \$::opt_arg_sep,
|
"arg-sep|argsep=s" => \$::opt_arg_sep,
|
||||||
|
@ -2301,7 +2302,7 @@ sub return {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my @return = ();
|
my @return = ();
|
||||||
for my $return (@{$self->{'commandline'}{'return_files'}}) {
|
for my $return (@{$self->{'commandline'}{'return_files'}}) {
|
||||||
CORE::push @return, $self->{'commandline'}->replace_placeholders($return);
|
CORE::push @return, $self->{'commandline'}->replace_placeholders($return,1);
|
||||||
}
|
}
|
||||||
return @return;
|
return @return;
|
||||||
}
|
}
|
||||||
|
@ -2452,14 +2453,17 @@ sub start {
|
||||||
print $Global::original_stderr "$command\n";
|
print $Global::original_stderr "$command\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if($Global::verbose and not $Global::grouped) {
|
if(($::opt_dryrun or $Global::verbose) and not $Global::grouped) {
|
||||||
if($Global::verbose == 1) {
|
if($Global::verbose <= 1) {
|
||||||
print STDOUT $job->replaced(),"\n";
|
print STDOUT $job->replaced(),"\n";
|
||||||
} else {
|
} else {
|
||||||
# Verbose level > 1: Print the rsync and stuff
|
# Verbose level > 1: Print the rsync and stuff
|
||||||
print STDOUT $command,"\n";
|
print STDOUT $command,"\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if($::opt_dryrun) {
|
||||||
|
$command = "true";
|
||||||
|
}
|
||||||
$Global::total_running++;
|
$Global::total_running++;
|
||||||
$Global::total_started++;
|
$Global::total_started++;
|
||||||
if(not $job->seq()) {
|
if(not $job->seq()) {
|
||||||
|
@ -2536,8 +2540,8 @@ sub print {
|
||||||
my $err = $self->stderr();
|
my $err = $self->stderr();
|
||||||
my ($command) = $self->sshlogin_wrap();
|
my ($command) = $self->sshlogin_wrap();
|
||||||
|
|
||||||
if($Global::verbose and $Global::grouped) {
|
if(($::opt_dryrun or $Global::verbose) and $Global::grouped) {
|
||||||
if($Global::verbose == 1) {
|
if($Global::verbose <= 1) {
|
||||||
print STDOUT $self->replaced(),"\n";
|
print STDOUT $self->replaced(),"\n";
|
||||||
} else {
|
} else {
|
||||||
# Verbose level > 1: Print the rsync and stuff
|
# Verbose level > 1: Print the rsync and stuff
|
||||||
|
@ -2838,7 +2842,7 @@ sub number_of_replacements {
|
||||||
sub replaced {
|
sub replaced {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
if(not defined $self->{'replaced'}) {
|
if(not defined $self->{'replaced'}) {
|
||||||
$self->{'replaced'} = $self->replace_placeholders($self->{'command'});
|
$self->{'replaced'} = $self->replace_placeholders($self->{'command'},0);
|
||||||
if($::opt_nice) {
|
if($::opt_nice) {
|
||||||
# Prepend nice -n19 bash -c
|
# Prepend nice -n19 bash -c
|
||||||
# and quote
|
# and quote
|
||||||
|
@ -2854,8 +2858,9 @@ sub replaced {
|
||||||
|
|
||||||
sub replace_placeholders {
|
sub replace_placeholders {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my($target) = shift;
|
my $target = shift;
|
||||||
my($context_replace) = $self->{'context_replace'};
|
my $quote_special_chars = shift;
|
||||||
|
my $context_replace = $self->{'context_replace'};
|
||||||
|
|
||||||
my $context_regexp = $context_replace ? '\S*' : ''; # Regexp to match surrounding context
|
my $context_regexp = $context_replace ? '\S*' : ''; # Regexp to match surrounding context
|
||||||
if($self->number_of_args() == 0) {
|
if($self->number_of_args() == 0) {
|
||||||
|
@ -2897,13 +2902,13 @@ sub replace_placeholders {
|
||||||
0 .. $#args);
|
0 .. $#args);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
die;
|
die('This should not happen. Contact <parallel@gnu.org>.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
my $replacements = 0;
|
my $replacements = 0;
|
||||||
if(%replace_single) {
|
if(%replace_single) {
|
||||||
my $single_regexp = join('|', map { $_=~s/(\W)/\\$1/g; $_} sort keys %replace_single);
|
my $single_regexp = join('|', map { $_=~s/(\W)/\\$1/g; $_} sort keys %replace_single);
|
||||||
$replacements += ($target =~ s/($single_regexp)/$replace_single{$1}/ge);
|
$replacements += ($target =~ s/($single_regexp)/$replace_single{$1}/ge);
|
||||||
}
|
}
|
||||||
my $orig_target = $target;
|
my $orig_target = $target;
|
||||||
|
@ -2913,29 +2918,62 @@ sub replace_placeholders {
|
||||||
$a=~s/(\W)/\\$1/g; $a
|
$a=~s/(\W)/\\$1/g; $a
|
||||||
} @used_multi);
|
} @used_multi);
|
||||||
my %wordargs;
|
my %wordargs;
|
||||||
while($target =~ s/(\S*($multi_regexp)\S*)/\0/o) {
|
if($quote_special_chars) {
|
||||||
my $wordarg = $1;
|
while($target =~ s/(.*($multi_regexp).*)/\0/o) {
|
||||||
my $pattern = $2;
|
my $wordarg = $1;
|
||||||
if($self->{'context_replace'}) {
|
my $pattern = $2;
|
||||||
my $substituted = $wordarg;
|
if($self->{'context_replace'}) {
|
||||||
my @all=();
|
|
||||||
for my $argref (@replace_context) {
|
|
||||||
# for each argument convert a{}b to a1b a2b
|
|
||||||
my $substituted = $wordarg;
|
my $substituted = $wordarg;
|
||||||
$substituted =~ s/($multi_regexp)/$argref->{$Global::replace_rev{$1}}/g;
|
my @all=();
|
||||||
CORE::push @all,$substituted;
|
for my $argref (@replace_context) {
|
||||||
|
# for each argument convert a{}b to a1b a2b
|
||||||
|
my $substituted = $wordarg;
|
||||||
|
$substituted =~ s/($multi_regexp)/$argref->{$Global::replace_rev{$1}}/g;
|
||||||
|
CORE::push @all,$substituted;
|
||||||
|
}
|
||||||
|
$wordargs{$wordarg} = join" ",@all;
|
||||||
|
return @all;
|
||||||
|
} else {
|
||||||
|
my $substituted = $wordarg;
|
||||||
|
$substituted =~ s/($multi_regexp)/join(" ",map {$_} @{$replace_multi{$Global::replace_rev{$1}}})/eg;
|
||||||
|
$wordargs{$wordarg} = $substituted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while($target =~ s/(\S*($multi_regexp)\S*)/\0/o) {
|
||||||
|
my $wordarg = $1;
|
||||||
|
my $pattern = $2;
|
||||||
|
if($self->{'context_replace'}) {
|
||||||
|
my $substituted = $wordarg;
|
||||||
|
my @all=();
|
||||||
|
for my $argref (@replace_context) {
|
||||||
|
# for each argument convert a{}b to a1b a2b
|
||||||
|
my $substituted = $wordarg;
|
||||||
|
$substituted =~ s/($multi_regexp)/$argref->{$Global::replace_rev{$1}}/g;
|
||||||
|
CORE::push @all,$substituted;
|
||||||
|
}
|
||||||
|
$wordargs{$wordarg} = join" ",@all;
|
||||||
|
} else {
|
||||||
|
my $substituted = $wordarg;
|
||||||
|
$substituted =~ s/($multi_regexp)/join(" ",map {$_} @{$replace_multi{$Global::replace_rev{$1}}})/eg;
|
||||||
|
$wordargs{$wordarg} = $substituted;
|
||||||
}
|
}
|
||||||
$wordargs{$wordarg} = join" ",@all;
|
|
||||||
} else {
|
|
||||||
my $substituted = $wordarg;
|
|
||||||
$substituted =~ s/($multi_regexp)/join(" ",map {$_} @{$replace_multi{$Global::replace_rev{$1}}})/eg;
|
|
||||||
$wordargs{$wordarg} = $substituted;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
my @k=keys %wordargs;
|
my @k=keys %wordargs;
|
||||||
for(@k) {s/(\W)/\\$1/g};
|
for(@k) {s/(\W)/\\$1/g};
|
||||||
my $regexp=join("|",@k);
|
my $regexp=join("|",@k);
|
||||||
$orig_target =~s/($regexp)/$wordargs{$1}/g;
|
if($quote_special_chars) {
|
||||||
|
# When --return'ing a file with added special chars
|
||||||
|
# they need to be quoted.
|
||||||
|
# E.g. --trc 'a {}'
|
||||||
|
# Not really pretty. Can this be done better?
|
||||||
|
$orig_target =~s/($regexp)/::shell_unquote($wordargs{$1})/ge;
|
||||||
|
$orig_target = ::shell_quote_scalar($orig_target);
|
||||||
|
} else {
|
||||||
|
$orig_target =~s/($regexp)/$wordargs{$1}/g;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return $orig_target;
|
return $orig_target;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Test if we can deal with output > 4 GB
|
# Test if we can deal with output > 4 GB
|
||||||
echo | niceload -l=1.5 parallel -q perl -e '$a="x"x1000000;for(0..4300){print $a}' | md5sum
|
echo | niceload -l 1.5 parallel -q perl -e '$a="x"x1000000;for(0..4300){print $a}' | md5sum
|
||||||
# dd does not work with niceload (no idea why)
|
# dd does not work with niceload (no idea why)
|
||||||
#echo | parallel 'dd if=/dev/zero count=43 bs=100000k; echo 1; echo 2' | md5sum
|
#echo | parallel 'dd if=/dev/zero count=43 bs=100000k; echo 1; echo 2' | md5sum
|
||||||
|
|
|
@ -27,9 +27,12 @@ SERVER1=parallel-server3
|
||||||
SERVER2=parallel-server2
|
SERVER2=parallel-server2
|
||||||
rm -rf tmp
|
rm -rf tmp
|
||||||
|
|
||||||
echo "### Test combined --return {/}_{/.}_{#/.}_{#/}_{#.}"
|
echo "### Test combined -X --return {/}_{/.}_{#/.}_{#/}_{#.} with files containing space"
|
||||||
stdout parallel -k -Xv --cleanup --return tmp/{/}_{/.}_{2/.}_{2/}_{2.}/file -S parallel@$SERVER2 \
|
stdout parallel -k -Xv --cleanup --return tmp/{/}_{/.}_{2/.}_{2/}_{2.}/file -S parallel@$SERVER2 \
|
||||||
mkdir -p tmp/{/}_{/.}_{2/.}_{2/}_{2.} \;touch tmp/{/}_{/.}_{2/.}_{2/}_{2.}/file \
|
mkdir -p tmp/{/}_{/.}_{2/.}_{2/}_{2.} \;touch tmp/{/}_{/.}_{2/.}_{2/}_{2.}/file \
|
||||||
::: /a/number1.c a/number2.c number3.c /a/number4 a/number5 number6
|
::: /a/number1.c a/number2.c number3.c /a/number4 a/number5 number6 'number 7' 'number <8|8>'
|
||||||
find tmp
|
find tmp
|
||||||
rm -rf tmp
|
rm -rf tmp
|
||||||
|
|
||||||
|
echo "### Here we ought to test -m --return {/}_{/.}_{#/.}_{#/}_{#.} with files containing space"
|
||||||
|
echo "### But we will wait for a real world scenario"
|
||||||
|
|
14
testsuite/tests-to-run/test46.sh
Normal file
14
testsuite/tests-to-run/test46.sh
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
SERVER1=parallel-server3
|
||||||
|
SERVER2=parallel-server2
|
||||||
|
|
||||||
|
echo '### Test --trc with space added in filename'
|
||||||
|
echo original > '/tmp/parallel space file'
|
||||||
|
echo '/tmp/parallel space file' | parallel --trc "{} more space" -S $SERVER1 cat {} ">{}\\ more\\ space"
|
||||||
|
cat '/tmp/parallel space file more space'
|
||||||
|
|
||||||
|
echo '### Test --trc with >|< added in filename'
|
||||||
|
echo original > '/tmp/parallel space file'
|
||||||
|
echo '/tmp/parallel space file' | parallel --trc "{} >|<" -S $SERVER1 cat {} ">{}\\ \\>\\|\\<"
|
||||||
|
cat '/tmp/parallel space file >|<'
|
2
testsuite/wanted-results/niceload01
Normal file
2
testsuite/wanted-results/niceload01
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
### Test niceload
|
||||||
|
..........
|
|
@ -24,13 +24,16 @@ number2
|
||||||
number2.c
|
number2.c
|
||||||
### Test {#.}
|
### Test {#.}
|
||||||
a/number2
|
a/number2
|
||||||
### Test combined --return {/}_{/.}_{#/.}_{#/}_{#.}
|
### Test combined -X --return {/}_{/.}_{#/.}_{#/}_{#.} with files containing space
|
||||||
Warning: using -X or -m with --sshlogin may fail
|
Warning: using -X or -m with --sshlogin may fail
|
||||||
mkdir -p tmp/number1.c_number1_number2_number2.c_a/number2 tmp/number2.c_number2_number2_number2.c_a/number2 tmp/number3.c_number3_number2_number2.c_a/number2 tmp/number4_number4_number2_number2.c_a/number2 tmp/number5_number5_number2_number2.c_a/number2 tmp/number6_number6_number2_number2.c_a/number2 ;touch tmp/number1.c_number1_number2_number2.c_a/number2/file tmp/number2.c_number2_number2_number2.c_a/number2/file tmp/number3.c_number3_number2_number2.c_a/number2/file tmp/number4_number4_number2_number2.c_a/number2/file tmp/number5_number5_number2_number2.c_a/number2/file tmp/number6_number6_number2_number2.c_a/number2/file
|
mkdir -p tmp/number1.c_number1_number2_number2.c_a/number2 tmp/number2.c_number2_number2_number2.c_a/number2 tmp/number3.c_number3_number2_number2.c_a/number2 tmp/number4_number4_number2_number2.c_a/number2 tmp/number5_number5_number2_number2.c_a/number2 tmp/number6_number6_number2_number2.c_a/number2 tmp/number\ 7_number\ 7_number2_number2.c_a/number2 tmp/number\ \<8\|8\>_number\ \<8\|8\>_number2_number2.c_a/number2 ;touch tmp/number1.c_number1_number2_number2.c_a/number2/file tmp/number2.c_number2_number2_number2.c_a/number2/file tmp/number3.c_number3_number2_number2.c_a/number2/file tmp/number4_number4_number2_number2.c_a/number2/file tmp/number5_number5_number2_number2.c_a/number2/file tmp/number6_number6_number2_number2.c_a/number2/file tmp/number\ 7_number\ 7_number2_number2.c_a/number2/file tmp/number\ \<8\|8\>_number\ \<8\|8\>_number2_number2.c_a/number2/file
|
||||||
tmp
|
tmp
|
||||||
tmp/number6_number6_number2_number2.c_a
|
tmp/number6_number6_number2_number2.c_a
|
||||||
tmp/number6_number6_number2_number2.c_a/number2
|
tmp/number6_number6_number2_number2.c_a/number2
|
||||||
tmp/number6_number6_number2_number2.c_a/number2/file
|
tmp/number6_number6_number2_number2.c_a/number2/file
|
||||||
|
tmp/number <8|8>_number <8|8>_number2_number2.c_a
|
||||||
|
tmp/number <8|8>_number <8|8>_number2_number2.c_a/number2
|
||||||
|
tmp/number <8|8>_number <8|8>_number2_number2.c_a/number2/file
|
||||||
tmp/number3.c_number3_number2_number2.c_a
|
tmp/number3.c_number3_number2_number2.c_a
|
||||||
tmp/number3.c_number3_number2_number2.c_a/number2
|
tmp/number3.c_number3_number2_number2.c_a/number2
|
||||||
tmp/number3.c_number3_number2_number2.c_a/number2/file
|
tmp/number3.c_number3_number2_number2.c_a/number2/file
|
||||||
|
@ -46,3 +49,8 @@ tmp/number1.c_number1_number2_number2.c_a/number2/file
|
||||||
tmp/number4_number4_number2_number2.c_a
|
tmp/number4_number4_number2_number2.c_a
|
||||||
tmp/number4_number4_number2_number2.c_a/number2
|
tmp/number4_number4_number2_number2.c_a/number2
|
||||||
tmp/number4_number4_number2_number2.c_a/number2/file
|
tmp/number4_number4_number2_number2.c_a/number2/file
|
||||||
|
tmp/number 7_number 7_number2_number2.c_a
|
||||||
|
tmp/number 7_number 7_number2_number2.c_a/number2
|
||||||
|
tmp/number 7_number 7_number2_number2.c_a/number2/file
|
||||||
|
### Here we ought to test -m --return {/}_{/.}_{#/.}_{#/}_{#.} with files containing space
|
||||||
|
### But we will wait for a real world scenario
|
||||||
|
|
4
testsuite/wanted-results/test46
Normal file
4
testsuite/wanted-results/test46
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
### Test --trc with space added in filename
|
||||||
|
original
|
||||||
|
### Test --trc with >|< added in filename
|
||||||
|
original
|
Loading…
Reference in a new issue