Released as 20240522 ('Tbilisi')
[parallel.git] / src / env_parallel.pdksh
blob1a25dcd5d97b4ac358269da1edd823c3ff885e61
1 #!/usr/bin/env pdksh
3 # This file must be sourced in pdksh:
5 #   source env_parallel.pdksh
7 # after which 'env_parallel' works
10 # Copyright (C) 2016-2024 Ole Tange, http://ole.tange.dk and Free
11 # Software Foundation, Inc.
13 # This program is free software; you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation; either version 3 of the License, or
16 # (at your option) any later version.
18 # This program is distributed in the hope that it will be useful, but
19 # WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21 # General Public License for more details.
23 # You should have received a copy of the GNU General Public License
24 # along with this program; if not, see <http://www.gnu.org/licenses/>
25 # or write to the Free Software Foundation, Inc., 51 Franklin St,
26 # Fifth Floor, Boston, MA 02110-1301 USA
28 # SPDX-FileCopyrightText: 2021-2024 Ole Tange, http://ole.tange.dk and Free Software and Foundation, Inc.
29 # SPDX-License-Identifier: GPL-3.0-or-later
31 env_parallel() {
32     # env_parallel.pdksh
34     _names_of_ALIASES() {
35         compgen -a
36     }
37     _bodies_of_ALIASES() {
38         alias "$@" | perl -pe 's/^/alias /'
39     }
40     _names_of_FUNCTIONS() {
41         compgen -A function
42     }
43     _bodies_of_FUNCTIONS() {
44         typeset -f "$@"
45     }
46     _names_of_VARIABLES() {
47         compgen -A variable
48     }
49     _bodies_of_VARIABLES() {
50         typeset -p "$@"
51     }
52     _remove_bad_NAMES() {
53         _tmp_READONLY="$(mktemp)"
54         readonly > "$_tmp_READONLY"
55         # Do not transfer vars and funcs from env_parallel
56         grep -Ev '^(_names_of_ALIASES|_bodies_of_ALIASES|_names_of_maybe_FUNCTIONS|_names_of_FUNCTIONS|_bodies_of_FUNCTIONS|_names_of_VARIABLES|_bodies_of_VARIABLES|_remove_bad_NAMES|_prefix_PARALLEL_ENV|_get_ignored_VARS|_make_grep_REGEXP|_ignore_UNDERSCORE|_alias_NAMES|_list_alias_BODIES|_function_NAMES|_list_function_BODIES|_variable_NAMES|_list_variable_VALUES|_prefix_PARALLEL_ENV|PARALLEL_ENV|PARALLEL_TMP)$' |
57             # Filter names matching --env
58             grep -E "^$_grep_REGEXP"\$ | grep -vE "^$_ignore_UNDERSCORE"\$ |
59             grep -vFf $_tmp_READONLY |
60             grep -Ev '^(PIPESTATUS)'
61         rm $_tmp_READONLY
62         unset _tmp_READONLY
63     }
64     _prefix_PARALLEL_ENV() {
65         shopt 2>/dev/null |
66         perl -pe 's:\s+off:;: and s/^/shopt -u /;
67                   s:\s+on:;: and s/^/shopt -s /;
68                   s:;$:&>/dev/null;:';
69         echo 'shopt -s expand_aliases &>/dev/null';
70     }
72     _get_ignored_VARS() {
73         perl -e '
74             for(@ARGV){
75                 $next_is_env and push @envvar, split/,/, $_;
76                 $next_is_env=/^--env$/;
77             }
78             if(grep { /^_$/ } @envvar) {
79                 if(not open(IN, "<", "$ENV{HOME}/.parallel/ignored_vars")) {
80                     print STDERR "parallel: Error: ",
81                     "Run \"parallel --record-env\" in a clean environment first.\n";
82                 } else {
83                     chomp(@ignored_vars = <IN>);
84                     $vars = join "|",map { quotemeta $_ } @ignored_vars;
85                     print $vars ? "($vars)" : "(,,nO,,VaRs,,)";
86                 }
87             }
88             ' -- "$@"
89     }
91     # Get the --env variables if set
92     # --env _ should be ignored
93     # and convert  a b c  to (a|b|c)
94     # If --env not set: Match everything (.*)
95     _make_grep_REGEXP() {
96         perl -e '
97             for(@ARGV){
98                 /^_$/ and $next_is_env = 0;
99                 $next_is_env and push @envvar, split/,/, $_;
100                 $next_is_env = /^--env$/;
101             }
102             $vars = join "|",map { quotemeta $_ } @envvar;
103             print $vars ? "($vars)" : "(.*)";
104             ' -- "$@"
105     }
107     if which parallel | grep 'no parallel in' >/dev/null; then
108         echo 'env_parallel: Error: parallel must be in $PATH.' >&2
109         return 1
110     fi
111     if which parallel >/dev/null; then
112         true which on linux
113     else
114         echo 'env_parallel: Error: parallel must be in $PATH.' >&2
115         return 1
116     fi
118     # Grep regexp for vars given by --env
119     _grep_REGEXP="`_make_grep_REGEXP \"$@\"`"
120     unset _make_grep_REGEXP
121     
122     # Deal with --env _
123     _ignore_UNDERSCORE="`_get_ignored_VARS \"$@\"`"
124     unset _get_ignored_VARS
126     # --record-env
127     if perl -e 'exit grep { /^--record-env$/ } @ARGV' -- "$@"; then
128         true skip
129     else
130         (_names_of_ALIASES;
131          _names_of_FUNCTIONS;
132          _names_of_VARIABLES) |
133             cat > $HOME/.parallel/ignored_vars
134         return 0
135     fi
136     
137     # Grep alias names
138     _alias_NAMES="`_names_of_ALIASES | _remove_bad_NAMES | xargs echo`"
139     _list_alias_BODIES="_bodies_of_ALIASES $_alias_NAMES"
140     if [ "$_alias_NAMES" = "" ] ; then
141         # no aliases selected
142         _list_alias_BODIES="true"
143     fi
144     unset _alias_NAMES
146     # Grep function names
147     _function_NAMES="`_names_of_FUNCTIONS | _remove_bad_NAMES | xargs echo`"
148     _list_function_BODIES="_bodies_of_FUNCTIONS $_function_NAMES"
149     if [ "$_function_NAMES" = "" ] ; then
150         # no functions selected
151         _list_function_BODIES="true"
152     fi
153     unset _function_NAMES
155     # Grep variable names
156     _variable_NAMES="`_names_of_VARIABLES | _remove_bad_NAMES | xargs echo`"
157     _list_variable_VALUES="_bodies_of_VARIABLES $_variable_NAMES"
158     if [ "$_variable_NAMES" = "" ] ; then
159         # no variables selected
160         _list_variable_VALUES="true"
161     fi
162     unset _variable_NAMES
164     # eval is needed for aliases - cannot explain why
165     export PARALLEL_ENV="`
166         eval $_list_alias_BODIES;
167         $_list_function_BODIES
168         $_list_variable_VALUES;
169     `";
170     unset _list_alias_BODIES _list_variable_VALUES _list_function_BODIES
171     unset _bodies_of_ALIASES _bodies_of_VARIABLES _bodies_of_FUNCTIONS
172     unset _names_of_ALIASES _names_of_VARIABLES _names_of_FUNCTIONS
173     unset _ignore_HARDCODED _ignore_READONLY _ignore_UNDERSCORE
174     unset _remove_bad_NAMES _grep_REGEXP
175     unset _prefix_PARALLEL_ENV
176     `which parallel` "$@"
177     _parallel_exit_CODE=$?
178     unset PARALLEL_ENV;
179     unset _which_PAR _which_TRUE
180     unset _warning_PAR _error_PAR
181     # Unset _parallel_exit_CODE before return
182     eval "unset _parallel_exit_CODE; return $_parallel_exit_CODE"