diff --git a/src/parallel b/src/parallel index e5be59d4..bfbe92e1 100755 --- a/src/parallel +++ b/src/parallel @@ -208,6 +208,7 @@ if($::opt_nonall or $::opt_onall) { ((defined $::opt_D) ? "-D" : ""), ((defined $::opt_timeout) ? "--timeout ".$::opt_timeout : ""), ((defined $::opt_plain) ? "--plain" : ""), + ((defined @::opt_env) ? map { "--env ".::shell_quote_scalar($_) } @::opt_env : ""), ); ::debug("| $0 $options\n"); open(PARALLEL,"| $0 -j0 $options") || @@ -605,7 +606,7 @@ sub get_options_from_array { sub parse_options { # Returns: N/A # Defaults: - $Global::version = 20120930; + $Global::version = 20121015; $Global::progname = 'parallel'; $Global::infinity = 2**31; $Global::debug = 0; @@ -837,6 +838,12 @@ sub parse_options { open_joblog(); } +sub env_quote { + my $v = shift; + $v =~ s/([ \n\&\<\>\(\)\;\'\{\}\t\"\$\`\*\174\!\?\~])/\\$1/g; + return $v; +} + sub parse_env_var { # Parse --env and set $Global::envvar # Returns: N/A @@ -846,15 +853,22 @@ sub parse_env_var { # Split up --env VAR1,VAR2 push @vars, split /,/, $varstring; } - $Global::envvar = - (q{eval `echo $SHELL | grep -E "/(t)?csh" > /dev/null} - . q{ && echo } - . join("", map { "setenv $_ " - . ::shell_quote_scalar(::shell_quote_scalar($ENV{$_})).'\;' } @vars) - . q{ || echo } - . join("", map { "export $_=" - . ::shell_quote_scalar(::shell_quote_scalar($ENV{$_})).'\;' } @vars) - .q{`;}); + # Keep only defined variables + @vars = grep { defined($ENV{$_}) } @vars; + my @qcsh = map { my $a=$_; "setenv $a " . env_quote($ENV{$a}) } @vars; + my @qbash = map { my $a=$_; "export $a=" . env_quote($ENV{$a}) } @vars; + + # Create lines like: + # echo $SHELL | grep -E "/t?csh" >/dev/null && setenv V1 val1 && setenv V2 val2 || export V1=val1 && export V2=val2 ; echo "$V1$V2" + if(@vars) { + $Global::envvar = + join"", + (q{echo $SHELL | grep -E "/t?csh" > /dev/null && } + . join(" && ", @qcsh) + . q{ || } + . join(" && ", @qbash) + .q{;}); + } $Global::envvarlen = length $Global::envvar; } @@ -1041,7 +1055,7 @@ sub __QUOTING_ARGUMENTS_FOR_SHELL__ {} sub shell_quote { my @strings = (@_); for my $a (@strings) { - $a =~ s/([\002-\011\013-\032\\\#\?\`\(\)\{\}\[\]\*\>\<\~\|\; \"\!\$\&\'])/\\$1/g; + $a =~ s/([\002-\011\013-\032\\\#\?\`\(\)\{\}\[\]\*\>\<\~\|\; \"\!\$\&\'\202-\377])/\\$1/g; $a =~ s/[\n]/'\n'/g; # filenames with '\n' is quoted using \' } return wantarray ? @strings : "@strings"; @@ -1052,7 +1066,7 @@ sub shell_quote_scalar { # Returns: # string quoted with \ as needed by the shell my $a = shift; - $a =~ s/([\002-\011\013-\032\\\#\?\`\(\)\{\}\[\]\*\>\<\~\|\; \"\!\$\&\'])/\\$1/g; + $a =~ s/([\002-\011\013-\032\\\#\?\`\(\)\{\}\[\]\*\>\<\~\|\; \"\!\$\&\'\202-\377])/\\$1/g; $a =~ s/[\n]/'\n'/g; # filenames with '\n' is quoted using \' return $a; } diff --git a/src/parallel.pod b/src/parallel.pod index 915ce0c5..629a43ca 100644 --- a/src/parallel.pod +++ b/src/parallel.pod @@ -445,6 +445,15 @@ If I 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. +=item B<--env> I + +Copy environment variable I. This will copy I to the +environment that the command is run in. This is especially useful for +remote environments. + +Caveat: If I contains newline ('\n') the value is messed up. + + =item B<--eta> Show the estimated number of seconds before finishing. This forces GNU diff --git a/testsuite/tests-to-run/parallel-local2.sh b/testsuite/tests-to-run/parallel-local2.sh index 8a24147f..c241dfdc 100644 --- a/testsuite/tests-to-run/parallel-local2.sh +++ b/testsuite/tests-to-run/parallel-local2.sh @@ -3,24 +3,28 @@ echo '### Test slow arguments generation - https://savannah.gnu.org/bugs/?32834' seq 1 3 | parallel -j1 "sleep 2; echo {}" | parallel -kj2 echo -echo '### Test --env - https://savannah.gnu.org/bugs/?37351' -export TWOSPACES=' 2 spaces ' -export THREESPACES=" > My brother's 12\" records < " -parallel --env TWOSPACES echo 'a"$TWOSPACES"b' ::: 1 -parallel --env TWOSPACES --env THREESPACES echo 'a"$TWOSPACES"b' 'a"$THREESPACES"b' ::: 2 -parallel --env TWOSPACES,THREESPACES echo 'a"$TWOSPACES"b' 'a"$THREESPACES"b' ::: 2a -parallel -S localhost --env TWOSPACES echo 'a"$TWOSPACES"b' ::: 1 -parallel -S localhost --env TWOSPACES --env THREESPACES echo 'a"$TWOSPACES"b' 'a"$THREESPACES"b' ::: 2 -parallel -S localhost --env TWOSPACES,THREESPACES echo 'a"$TWOSPACES"b' 'a"$THREESPACES"b' ::: 2a -parallel -S csh@localhost --env TWOSPACES echo 'a"$TWOSPACES"b' ::: 1 -parallel -S csh@localhost --env TWOSPACES --env THREESPACES echo 'a"$TWOSPACES"b' 'a"$THREESPACES"b' ::: 2 -parallel -S csh@localhost --env TWOSPACES,THREESPACES echo 'a"$TWOSPACES"b' 'a"$THREESPACES"b' ::: 2a - echo '### Test too slow spawning' killall -9 burnP6 2>/dev/null -seq 1 2 | parallel -j2 -N0 timeout -k 25 26 burnP6 & +seq `parallel --number-of-cores` | parallel -j100% -N0 timeout -k 25 26 burnP6 & sleep 1 seq 1 1000 | stdout nice nice parallel -s 100 -uj0 true | perl -pe '/parallel: Warning: Starting \d+ processes took/ and do {close STDIN; `killall -9 burnP6`; print "OK\n"; exit }' killall -9 burnP6 2>/dev/null + +echo '### Test --env - https://savannah.gnu.org/bugs/?37351' +export TWOSPACES=' 2 spaces ' +export THREESPACES=" > My brother's 12\" records < " +stdout parallel --env TWOSPACES echo 'a"$TWOSPACES"b' ::: 1 +stdout parallel --env TWOSPACES --env THREESPACES echo 'a"$TWOSPACES"b' 'a"$THREESPACES"b' ::: 2 +stdout parallel --env TWOSPACES,THREESPACES echo 'a"$TWOSPACES"b' 'a"$THREESPACES"b' ::: 2a +stdout parallel -S localhost --env TWOSPACES echo 'a"$TWOSPACES"b' ::: 1 +stdout parallel -S localhost --env TWOSPACES --env THREESPACES echo 'a"$TWOSPACES"b' 'a"$THREESPACES"b' ::: 2 +stdout parallel -S localhost --env TWOSPACES,THREESPACES echo 'a"$TWOSPACES"b' 'a"$THREESPACES"b' ::: 2a + +echo '### Test --env all chars except \n - single and double - no output is good' +perl -e 'for(1..9,9,11..255) { printf "%c%c %c%d\0",$_,$_,$_,$_ }' | stdout parallel --nice 19 -j4 -k -I // --arg-sep _ -0 V=// V2=V2=// parallel -k -j1 -S :,1/lo,1/tcsh@lo,1/csh@lo --env V,V2 echo \''"{}$V$V2"'\' ::: {#} {#} {#} {#} | uniq -c | grep -v ' 4 '|grep -v xauth |grep -v X11 + +echo '### Test --env all chars except \n - single and double --onall - no output is good' +perl -e 'for(1..9,9,11..255) { printf "%c%c %c%d\0",$_,$_,$_,$_ }' | stdout parallel --nice 19 -j4 -k -I // --arg-sep _ -0 V=// V2=V2=// parallel -k -j1 -S :,1/lo,1/tcsh@lo,1/csh@lo --onall --env V,V2 echo \''"{}$V$V2"'\' ::: {#} | uniq -c | grep -v ' 4 '|grep -v xauth |grep -v X11 + diff --git a/testsuite/wanted-results/parallel-local2 b/testsuite/wanted-results/parallel-local2 index 55a91f5e..42e0a62a 100644 --- a/testsuite/wanted-results/parallel-local2 +++ b/testsuite/wanted-results/parallel-local2 @@ -4,3 +4,12 @@ 3 ### Test too slow spawning OK +### Test --env - https://savannah.gnu.org/bugs/?37351 +a 2 spaces b 1 +a 2 spaces b a > My brother's 12" records < b 2 +a 2 spaces b a > My brother's 12" records < b 2a +a 2 spaces b 1 +a 2 spaces b a > My brother's 12" records < b 2 +a 2 spaces b a > My brother's 12" records < b 2a +### Test --env all chars except \n - single and double - no output is good +### Test --env all chars except \n - single and double --onall - no output is good