summaryrefslogtreecommitdiffstats
path: root/src/env_parallel
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xsrc/env_parallel145
-rwxr-xr-xsrc/env_parallel.ash636
-rwxr-xr-xsrc/env_parallel.bash640
-rwxr-xr-xsrc/env_parallel.csh142
-rwxr-xr-xsrc/env_parallel.dash636
-rwxr-xr-xsrc/env_parallel.fish194
-rwxr-xr-xsrc/env_parallel.ksh636
-rw-r--r--src/env_parallel.mksh605
-rwxr-xr-xsrc/env_parallel.pdksh183
-rw-r--r--src/env_parallel.pod942
-rwxr-xr-xsrc/env_parallel.sh636
-rwxr-xr-xsrc/env_parallel.tcsh142
-rwxr-xr-xsrc/env_parallel.zsh636
13 files changed, 6173 insertions, 0 deletions
diff --git a/src/env_parallel b/src/env_parallel
new file mode 100755
index 0000000..0f05192
--- /dev/null
+++ b/src/env_parallel
@@ -0,0 +1,145 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2016-2024 Ole Tange, http://ole.tange.dk and 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/>
+# or write to the Free Software Foundation, Inc., 51 Franklin St,
+# Fifth Floor, Boston, MA 02110-1301 USA
+#
+# SPDX-FileCopyrightText: 2021-2024 Ole Tange, http://ole.tange.dk and Free Software and Foundation, Inc.
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+grepq() {
+ # grep -q for systems without -q
+ grep >/dev/null 2>/dev/null "$@"
+}
+
+installer() {
+ source="$1"
+ script="$2"
+ into="$3"
+ if grepq $script "$into"; then
+ true already installed
+ else
+ echo $source \`which $script\` >> "$into"
+ fi
+}
+
+while test $# -gt 0; do
+ key="$1"
+
+ case $key in
+ -i|--install)
+ installer . env_parallel.bash "$HOME"/.bashrc
+ installer . env_parallel.sh "$HOME"/.shrc
+ installer . env_parallel.zsh "$HOME"/.zshenv
+ installer source env_parallel.ksh "$HOME"/.kshrc
+ installer source env_parallel.mksh "$HOME"/.mkshrc
+ echo $SHELL | grepq /pdksh &&
+ installer . env_parallel.pdksh "$HOME"/.profile
+ echo $SHELL | grepq /ash &&
+ installer . env_parallel.ash "$HOME"/.profile
+ echo $SHELL | grepq /dash &&
+ installer . env_parallel.dash "$HOME"/.profile
+ installer source env_parallel.csh "$HOME"/.cshrc
+ installer source env_parallel.tcsh "$HOME"/.tcshrc
+ mkdir -p "$HOME"/.config/fish
+ grepq env_parallel.fish "$HOME"/.config/fish/config.fish ||
+ echo '. (which env_parallel.fish)' >> "$HOME"/.config/fish/config.fish
+ echo 'Installed env_parallel in:'
+ echo " " "$HOME"/.bashrc
+ echo " " "$HOME"/.shrc
+ echo " " "$HOME"/.zshenv
+ echo " " "$HOME"/.config/fish/config.fish
+ echo " " "$HOME"/.kshrc
+ echo " " "$HOME"/.mkshrc
+ echo " " "$HOME"/.profile
+ echo " " "$HOME"/.cshrc
+ echo " " "$HOME"/.tcshrc
+ exit
+ ;;
+ *)
+ echo "Unknown option: $key"
+ ;;
+ esac
+ shift # past argument or value
+done
+
+
+cat <<'_EOS'
+You have called the dummy script "env_parallel".
+
+env_parallel only works if it is a function.
+
+You need to do this and restart your shell:
+
+bash: Put this in $HOME/.bashrc: . env_parallel.bash
+ E.g. by doing: echo '. env_parallel.bash' >> $HOME/.bashrc
+ Supports: variables, aliases, functions, arrays
+
+fish: Put this in $HOME/.config/fish/config.fish: . (which env_parallel.fish)
+ E.g. by doing:
+ echo '. (which env_parallel.fish)' >> $HOME/.config/fish/config.fish
+ Supports: variables, aliases, functions, arrays
+
+ksh: Put this in $HOME/.kshrc: source env_parallel.ksh
+ E.g. by doing: echo 'source env_parallel.ksh' >> $HOME/.kshrc
+ Supports: variables, aliases, functions, arrays
+
+mksh: Put this in $HOME/.mkshrc: source env_parallel.mksh
+ E.g. by doing: echo 'source env_parallel.mksh' >> $HOME/.mkshrc
+ Supports: variables, aliases, functions, arrays
+
+pdksh: Put this in $HOME/.profile: source env_parallel.pdksh
+ E.g. by doing: echo '. env_parallel.pdksh' >> $HOME/.profile
+ Supports: variables, aliases, functions, arrays
+
+zsh: Put this in $HOME/.zshrc: . env_parallel.zsh
+ E.g. by doing: echo '. env_parallel.zsh' >> $HOME/.zshenv
+ Supports: variables, functions, arrays
+
+ash: Put this in $HOME/.profile: . env_parallel.ash
+ E.g. by doing: echo '. env_parallel.ash' >> $HOME/.profile
+ Supports: variables, aliases
+
+dash: Put this in $HOME/.profile: . env_parallel.dash
+ E.g. by doing: echo '. env_parallel.dash' >> $HOME/.profile
+ Supports: variables, aliases
+
+csh: Put this in $HOME/.cshrc: source `which env_parallel.csh`
+ E.g. by doing: echo 'source `which env_parallel.csh`' >> $HOME/.cshrc
+ Supports: variables, aliases, arrays with no special chars
+
+tcsh: Put this in $HOME/.tcshrc: source `which env_parallel.tcsh`
+ E.g. by doing: echo 'source `which env_parallel.tcsh`' >> $HOME/.tcshrc
+ Supports: variables, aliases, arrays with no special chars
+
+To install in all shells run:
+
+ env_parallel --install
+
+In a script you need to run this before using env_parallel:
+
+bash: . env_parallel.bash
+ksh: source env_parallel.ksh
+mksh: source env_parallel.mksh
+pdksh: source env_parallel.pdksh
+zsh: . env_parallel.zsh
+ash: . env_parallel.ash
+dash: . env_parallel.dash
+
+For details: see man env_parallel
+
+_EOS
diff --git a/src/env_parallel.ash b/src/env_parallel.ash
new file mode 100755
index 0000000..b41f76e
--- /dev/null
+++ b/src/env_parallel.ash
@@ -0,0 +1,636 @@
+#!/usr/bin/env ash
+
+# This file must be sourced in sh/ash/dash/bash/ksh/mksh/zsh:
+#
+# . env_parallel.sh
+# source env_parallel.ash
+# source env_parallel.dash
+# source env_parallel.bash
+# source env_parallel.ksh
+# source env_parallel.mksh
+# source env_parallel.zsh
+#
+# after which 'env_parallel' works
+#
+#
+# Copyright (C) 2016-2024 Ole Tange, http://ole.tange.dk and 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/>
+# or write to the Free Software Foundation, Inc., 51 Franklin St,
+# Fifth Floor, Boston, MA 02110-1301 USA
+#
+# SPDX-FileCopyrightText: 2021-2024 Ole Tange, http://ole.tange.dk and Free Software and Foundation, Inc.
+# SPDX-License-Identifier: GPL-3.0-or-later
+# shellcheck disable=SC2006
+
+env_parallel() {
+ # env_parallel.{sh,ash,dash,bash,ksh,mksh,zsh}
+
+ # Check shell dialect
+ if [ -n "$BASH_VERSION" ]; then
+ _shell_DIALECT=bash
+ _eval_needed=false
+ _prefix_PARALLEL_ENV=_prefix_PARALLEL_ENV_bash
+ elif [ -n "$ZSH_VERSION" ]; then
+ _shell_DIALECT=zsh
+ _eval_needed=true
+ _prefix_PARALLEL_ENV=false
+ elif [ -n "$KSH_VERSION" ]; then
+ _shell_DIALECT=ksh
+ _eval_needed=false
+ _prefix_PARALLEL_ENV=false
+ else
+ # Dash/ash - can these be detected better?
+ _shell_DIALECT="sh"
+ _eval_needed=false
+ _prefix_PARALLEL_ENV=false
+ fi
+ _names_of_ALIASES() {
+ _names_of_ALIASES_$_shell_DIALECT
+ }
+ _names_of_ALIASES_sh() {
+ # alias fails on Unixware 5
+ for _i in `alias 2>/dev/null | perl -ne 's/^alias //;s/^(\S+)=.*/$1/ && print' 2>/dev/null`; do
+ # Check if this name really is an alias
+ # or just part of a multiline alias definition
+ if alias "$_i" >/dev/null 2>/dev/null; then
+ echo "$_i"
+ fi
+ done
+ }
+ _names_of_ALIASES_bash() {
+ # No aliases will return false. This error should be ignored.
+ # shellcheck disable=SC3044
+ compgen -a || true
+ }
+ _names_of_ALIASES_ksh() {
+ alias | perl -pe 's/=.*//'
+ }
+ _names_of_ALIASES_zsh() {
+ # shellcheck disable=SC2086,SC2296
+ print -l ${(k)aliases}
+ }
+ _bodies_of_ALIASES() {
+ _bodies_of_ALIASES_$_shell_DIALECT "$@"
+ }
+ _bodies_of_ALIASES_sh() {
+ # alias may return:
+ # myalias='definition' (GNU/Linux ash)
+ # alias myalias='definition' (FreeBSD ash)
+ # so remove 'alias ' from first line
+ for _i in "$@"; do
+ echo 'alias '"`alias "$_i" | perl -pe '1..1 and s/^alias //'`"
+ done
+ }
+ _bodies_of_ALIASES_bash() {
+ # shellcheck disable=SC3043
+ local _i
+ for _i in "$@"; do
+ # shellcheck disable=SC2046
+ if [ $(alias "$_i" | wc -l) = 1 ] ; then
+ true Alias is a single line. Good.
+ else
+ _warning_PAR "Alias '$_i' contains newline."
+ _warning_PAR "Make sure the command has at least one newline after '$_i'."
+ _warning_PAR "See BUGS in 'man env_parallel'."
+ fi
+ done
+ alias "$@"
+ }
+ _bodies_of_ALIASES_ksh() {
+ alias "$@" | perl -pe 's/^/alias /;
+ sub warning { print STDERR "env_parallel: Warning: @_\n"; }
+ if(/^alias (\S+)=\$.*\\n/) {
+ warning("Alias \"$1\" contains newline.");
+ warning("Make sure the command has at least one newline after \"$1\".");
+ warning("See BUGS in \"man env_parallel\".");
+ }'
+
+ }
+ _bodies_of_ALIASES_zsh() {
+ # shellcheck disable=SC3043
+ local _i
+ for _i in "$@"; do
+ echo 'alias '"$(alias "$_i")"
+ done
+ }
+ _names_of_FUNCTIONS() {
+ _names_of_FUNCTIONS_$_shell_DIALECT
+ }
+ _names_of_FUNCTIONS_bash() {
+ # shellcheck disable=SC3044
+ compgen -A function
+ }
+ _names_of_maybe_FUNCTIONS() {
+ set | perl -ne '/^([A-Z_0-9]+)\s*\(\)\s*\{?$/i and print "$1\n"'
+ }
+ _names_of_FUNCTIONS_sh() {
+ # myfunc is a function
+ # shellcheck disable=SC2046
+ LANG=C type `_names_of_maybe_FUNCTIONS` |
+ perl -ne '/^(\S+) is a function$/ and not $seen{$1}++ and print "$1\n"'
+ }
+ _names_of_FUNCTIONS_ksh() {
+ # shellcheck disable=SC3044
+ typeset +f | perl -pe 's/\(\).*//; s/ .*//;'
+ }
+ _names_of_FUNCTIONS_zsh() {
+ # shellcheck disable=SC2086,SC2296
+ print -l ${(k)functions}
+ }
+ _bodies_of_FUNCTIONS() {
+ _bodies_of_FUNCTIONS_$_shell_DIALECT "$@"
+ }
+ _bodies_of_FUNCTIONS_sh() {
+ LANG=C type "$@" | perl -ne '/^(\S+) is a function$/ or print'
+ }
+ _bodies_of_FUNCTIONS_bash() {
+ # shellcheck disable=SC3044
+ typeset -f "$@"
+ }
+ _bodies_of_FUNCTIONS_ksh() {
+ functions "$@"
+ }
+ _bodies_of_FUNCTIONS_zsh() {
+ # shellcheck disable=SC3044
+ typeset -f "$@"
+ }
+ _names_of_VARIABLES() {
+ _names_of_VARIABLES_$_shell_DIALECT
+ }
+ _names_of_VARIABLES_sh() {
+ # This may screw up if variables contain \n and =
+ set | perl -ne 's/^(\S+?)=.*/$1/ and print;'
+ }
+ _names_of_VARIABLES_bash() {
+ # shellcheck disable=SC3044
+ compgen -A variable
+ }
+ _names_of_VARIABLES_ksh() {
+ # shellcheck disable=SC3044
+ typeset +p |
+ perl -pe 's/^(type)?set( [-+][a-zA-Z0-9]*)* //; s/(\[\d+\])?=.*//' |
+ uniq
+ }
+ _names_of_VARIABLES_zsh() {
+ # shellcheck disable=SC2086,SC2296
+ print -l ${(k)parameters}
+ }
+ _bodies_of_VARIABLES() {
+ _bodies_of_VARIABLES_$_shell_DIALECT "$@"
+ }
+ _bodies_of_VARIABLES_sh() {
+ # Crappy typeset -p
+ for _i in "$@"
+ do
+ perl -e 'print @ARGV' "$_i="
+ eval echo "\"\$$_i\"" | perl -e '$/=undef; $a=<>; chop($a); print $a' |
+ perl -pe 's/[\002-\011\013-\032\\\#\?\`\(\)\{\}\[\]\^\*\<\=\>\~\|\; \"\!\$\&\202-\377]/\\$&/go;'"s/'/\\\'/g; s/[\n]/'\\n'/go;";
+ echo
+ done
+ }
+ _bodies_of_VARIABLES_bash() {
+ # shellcheck disable=SC3044
+ typeset -p "$@"
+ }
+ _bodies_of_VARIABLES_ksh() {
+ # shellcheck disable=SC3044
+ typeset -p "$@"
+ }
+ _bodies_of_VARIABLES_zsh() {
+ # shellcheck disable=SC3044
+ typeset -p "$@"
+ }
+ _ignore_HARDCODED() {
+ _ignore_HARDCODED_$_shell_DIALECT
+ }
+ _ignore_HARDCODED_sh() {
+ # These names cannot be detected
+ echo '(_|TIMEOUT|IFS)'
+ }
+ _ignore_HARDCODED_bash() {
+ # Copying $RANDOM will cause it not to be random
+ # The rest cannot be detected as read-only
+ echo '(RANDOM|_|TIMEOUT|GROUPS|FUNCNAME|DIRSTACK|PIPESTATUS|USERNAME|BASHPID|BASH_[A-Z_]+)'
+ }
+ _ignore_HARDCODED_ksh() {
+ # These names cannot be detected
+ echo '(_|TIMEOUT|IFS)'
+ }
+ _ignore_HARDCODED_zsh() {
+ # These names cannot be detected
+ echo '([-\?\#\!\$\*\@\_0]|zsh_eval_context|ZSH_EVAL_CONTEXT|LINENO|IFS|commands|functions|options|aliases|EUID|EGID|UID|GID|dis_patchars|patchars|terminfo|galiases|keymaps|parameters|jobdirs|dirstack|functrace|funcsourcetrace|zsh_scheduled_events|dis_aliases|dis_reswords|dis_saliases|modules|reswords|saliases|widgets|userdirs|historywords|nameddirs|termcap|dis_builtins|dis_functions|jobtexts|funcfiletrace|dis_galiases|builtins|history|jobstates|funcstack|run-help)'
+ }
+ _ignore_READONLY() {
+ _ignore_READONLY_$_shell_DIALECT
+ }
+ _parse_READONLY() {
+ # shellcheck disable=SC1078,SC1079,SC2026
+ perl -e '@r = map {
+ chomp;
+ # sh on UnixWare: readonly TIMEOUT
+ # ash: readonly var='val'
+ # ksh: var='val'
+ # mksh: PIPESTATUS[0]
+ s/^(readonly )?([^=\[ ]*?)(\[\d+\])?(=.*|)$/$2/ or
+ # bash: declare -ar BASH_VERSINFO=([0]="4" [1]="4")
+ # zsh: typeset -r var='val'
+ s/^\S+\s+\S+\s+(\S[^=]*)(=.*|$)/$1/;
+ $_ } <>;
+ $vars = join "|",map { quotemeta $_ } @r;
+ print $vars ? "($vars)" : "(,,nO,,VaRs,,)";
+ '
+ }
+ _ignore_READONLY_sh() {
+ readonly | _parse_READONLY
+ }
+ _ignore_READONLY_bash() {
+ readonly | _parse_READONLY
+ }
+ _ignore_READONLY_ksh() {
+ readonly | _parse_READONLY
+ }
+ _ignore_READONLY_zsh() {
+ # shellcheck disable=SC3044
+ typeset -pr | _parse_READONLY
+ }
+ _remove_bad_NAMES() {
+ # Do not transfer vars and funcs from env_parallel
+ # shellcheck disable=SC2006
+ _ignore_RO="`_ignore_READONLY`"
+ # shellcheck disable=SC2006
+ _ignore_HARD="`_ignore_HARDCODED`"
+ # To avoid depending on grep dialect, use Perl version of:
+ # grep -Ev '^(...)$' |
+ perl -ne '/^(
+ PARALLEL_ENV|
+ PARALLEL_TMP|
+ _alias_NAMES|
+ _bodies_of_ALIASES|
+ _bodies_of_FUNCTIONS|
+ _bodies_of_VARIABLES|
+ _error_PAR|
+ _function_NAMES|
+ _get_ignored_VARS|
+ _grep_REGEXP|
+ _ignore_HARD|
+ _ignore_HARDCODED|
+ _ignore_READONLY|
+ _ignore_RO|
+ _ignore_UNDERSCORE|
+ _list_alias_BODIES|
+ _list_function_BODIES|
+ _list_variable_VALUES|
+ _make_grep_REGEXP|
+ _names_of_ALIASES|
+ _names_of_FUNCTIONS|
+ _names_of_VARIABLES|
+ _names_of_maybe_FUNCTIONS|
+ _parallel_exit_CODE|
+ _prefix_PARALLEL_ENV|
+ _prefix_PARALLEL_ENV_bash|
+ _remove_bad_NAMES|
+ _remove_readonly|
+ _variable_NAMES|
+ _warning_PAR|
+ _which_PAR)$/x and next;
+ # Filter names matching --env
+ /^'"$_grep_REGEXP"'$/ or next;
+ /^'"$_ignore_UNDERSCORE"'$/ and next;
+ # Remove readonly variables
+ /^'"$_ignore_RO"'$/ and next;
+ /^'"$_ignore_HARD"'$/ and next;
+ print;'
+ }
+ _prefix_PARALLEL_ENV_bash() {
+ # shellcheck disable=SC3044
+ shopt 2>/dev/null |
+ perl -pe 's:\s+off:;: and s/^/shopt -u /;
+ s:\s+on:;: and s/^/shopt -s /;
+ s:;$:&>/dev/null;:';
+ echo 'shopt -s expand_aliases &>/dev/null';
+ }
+
+ _get_ignored_VARS() {
+ perl -e '
+ for(@ARGV){
+ $next_is_env and push @envvar, split/,/, $_;
+ $next_is_env=/^--env$/;
+ }
+ if(grep { /^_$/ } @envvar) {
+ if(not open(IN, "<", "$ENV{HOME}/.parallel/ignored_vars")) {
+ print STDERR "parallel: Error: ",
+ "Run \"parallel --record-env\" in a clean environment first.\n";
+ } else {
+ chomp(@ignored_vars = <IN>);
+ }
+ }
+ if($ENV{PARALLEL_IGNORED_NAMES}) {
+ push @ignored_vars, split/\s+/, $ENV{PARALLEL_IGNORED_NAMES};
+ chomp @ignored_vars;
+ }
+ $vars = join "|",map { quotemeta $_ } @ignored_vars;
+ print $vars ? "($vars)" : "(,,nO,,VaRs,,)";
+ ' -- "$@"
+ }
+
+ # Get the --env variables if set
+ # --env _ should be ignored
+ # and convert a b c to (a|b|c)
+ # If --env not set: Match everything (.*)
+ _make_grep_REGEXP() {
+ perl -e '
+ for(@ARGV){
+ /^_$/ and $next_is_env = 0;
+ $next_is_env and push @envvar, split/,/, $_;
+ $next_is_env = /^--env$/;
+ }
+ $vars = join "|",map { quotemeta $_ } @envvar;
+ print $vars ? "($vars)" : "(.*)";
+ ' -- "$@"
+ }
+ _which_PAR() {
+ # type returns:
+ # ll is an alias for ls -l (in ash)
+ # bash is a tracked alias for /bin/bash
+ # true is a shell builtin (in bash)
+ # myfunc is a function (in bash)
+ # myfunc is a shell function (in zsh)
+ # which is /usr/bin/which (in sh, bash)
+ # which is hashed (/usr/bin/which)
+ # gi is aliased to `grep -i' (in bash)
+ # aliased to `alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
+ # Return 0 if found, 1 otherwise
+ LANG=C type "$@" |
+ perl -pe '$exit += (s/ is an alias for .*// ||
+ s/ is aliased to .*// ||
+ s/ is a function// ||
+ s/ is a shell function// ||
+ s/ is a shell builtin// ||
+ s/.* is hashed .(\S+).$/$1/ ||
+ s/.* is (a tracked alias for )?//);
+ END { exit not $exit }'
+ }
+ _warning_PAR() {
+ echo "env_parallel: Warning: $*" >&2
+ }
+ _error_PAR() {
+ echo "env_parallel: Error: $*" >&2
+ }
+
+ if _which_PAR parallel >/dev/null; then
+ true parallel found in path
+ else
+ # shellcheck disable=SC2016
+ _error_PAR 'parallel must be in $PATH.'
+ return 255
+ fi
+
+ # Grep regexp for vars given by --env
+ # shellcheck disable=SC2006
+ _grep_REGEXP="`_make_grep_REGEXP \"$@\"`"
+ unset _make_grep_REGEXP
+
+ # Deal with --env _
+ # shellcheck disable=SC2006
+ _ignore_UNDERSCORE="`_get_ignored_VARS \"$@\"`"
+ unset _get_ignored_VARS
+
+ # --record-env
+ if perl -e 'exit grep { /^--record-env$/ } @ARGV' -- "$@"; then
+ true skip
+ else
+ (_names_of_ALIASES;
+ _names_of_FUNCTIONS;
+ _names_of_VARIABLES) |
+ cat > "$HOME"/.parallel/ignored_vars
+ return 0
+ fi
+
+ # --session
+ if perl -e 'exit grep { /^--session$/ } @ARGV' -- "$@"; then
+ true skip
+ else
+ # Insert ::: between each level of session
+ # so you can pop off the last ::: at --end-session
+ # shellcheck disable=SC2006
+ PARALLEL_IGNORED_NAMES="`echo \"$PARALLEL_IGNORED_NAMES\";
+ echo :::;
+ (_names_of_ALIASES;
+ _names_of_FUNCTIONS;
+ _names_of_VARIABLES) | perl -ne '
+ BEGIN{
+ map { $ignored_vars{$_}++ }
+ split/\s+/, $ENV{PARALLEL_IGNORED_NAMES};
+ }
+ chomp;
+ for(split/\s+/) {
+ if(not $ignored_vars{$_}) {
+ print $_,\"\\n\";
+ }
+ }
+ '`"
+ export PARALLEL_IGNORED_NAMES
+ return 0
+ fi
+ if perl -e 'exit grep { /^--end.?session$/ } @ARGV' -- "$@"; then
+ true skip
+ else
+ # Pop off last ::: from PARALLEL_IGNORED_NAMES
+ # shellcheck disable=SC2006
+ PARALLEL_IGNORED_NAMES="`perl -e '
+ $ENV{PARALLEL_IGNORED_NAMES} =~ s/(.*):::.*?$/$1/s;
+ print $ENV{PARALLEL_IGNORED_NAMES}
+ '`"
+ return 0
+ fi
+ # Grep alias names
+ # shellcheck disable=SC2006
+ _alias_NAMES="`_names_of_ALIASES | _remove_bad_NAMES | xargs echo`"
+ _list_alias_BODIES="_bodies_of_ALIASES $_alias_NAMES"
+ if [ "$_alias_NAMES" = "" ] ; then
+ # no aliases selected
+ _list_alias_BODIES="true"
+ fi
+ unset _alias_NAMES
+
+ # Grep function names
+ # shellcheck disable=SC2006
+ _function_NAMES="`_names_of_FUNCTIONS | _remove_bad_NAMES | xargs echo`"
+ _list_function_BODIES="_bodies_of_FUNCTIONS $_function_NAMES"
+ if [ "$_function_NAMES" = "" ] ; then
+ # no functions selected
+ _list_function_BODIES="true"
+ fi
+ unset _function_NAMES
+
+ # Grep variable names
+ # shellcheck disable=SC2006
+ _variable_NAMES="`_names_of_VARIABLES | _remove_bad_NAMES | xargs echo`"
+ _list_variable_VALUES="_bodies_of_VARIABLES $_variable_NAMES"
+ if [ "$_variable_NAMES" = "" ] ; then
+ # no variables selected
+ _list_variable_VALUES="true"
+ fi
+ unset _variable_NAMES
+
+ if $_eval_needed ; then
+ # shellcheck disable=SC2006
+ PARALLEL_ENV="`
+ eval $_prefix_PARALLEL_ENV;
+ eval $_list_alias_BODIES;
+ eval $_list_function_BODIES;
+ eval $_list_variable_VALUES;
+ `"
+ else
+ # shellcheck disable=SC2006
+ PARALLEL_ENV="`
+ $_prefix_PARALLEL_ENV;
+ $_list_alias_BODIES;
+ $_list_function_BODIES;
+ $_list_variable_VALUES;
+ `"
+ fi
+ export PARALLEL_ENV
+ # Free up some env space
+ unset _list_alias_BODIES _list_variable_VALUES _list_function_BODIES
+ unset _bodies_of_ALIASES _bodies_of_VARIABLES _bodies_of_FUNCTIONS
+ unset _names_of_ALIASES _names_of_VARIABLES _names_of_FUNCTIONS
+ unset _ignore_HARDCODED _ignore_READONLY _ignore_UNDERSCORE
+ unset _remove_bad_NAMES _grep_REGEXP _parse_READONLY
+ unset _prefix_PARALLEL_ENV
+ unset _ignore_READONLY_sh _ignore_READONLY_bash
+ unset _ignore_READONLY_ksh _ignore_READONLY_zsh
+ unset _ignore_HARDCODED_sh _ignore_HARDCODED_bash
+ unset _ignore_HARDCODED_ksh _ignore_HARDCODED_zsh
+ unset _bodies_of_ALIASES_ksh _bodies_of_ALIASES_sh
+ unset _bodies_of_ALIASES_zsh _bodies_of_FUNCTIONS_bash
+ unset _bodies_of_FUNCTIONS_ksh _bodies_of_FUNCTIONS_sh
+ unset _bodies_of_FUNCTIONS_zsh _bodies_of_VARIABLES_bash
+ unset _bodies_of_VARIABLES_ksh _bodies_of_VARIABLES_sh
+ unset _bodies_of_VARIABLES_zsh
+ unset _names_of_ALIASES _names_of_ALIASES_bash
+ unset _names_of_ALIASES_ksh _names_of_ALIASES_sh
+ unset _names_of_ALIASES_zsh _names_of_FUNCTIONS
+ unset _names_of_FUNCTIONS_bash _names_of_FUNCTIONS_ksh
+ unset _names_of_FUNCTIONS_sh _names_of_FUNCTIONS_zsh
+ unset _names_of_VARIABLES _names_of_VARIABLES_bash
+ unset _names_of_VARIABLES_ksh _names_of_VARIABLES_sh
+ unset _names_of_VARIABLES_zsh _names_of_maybe_FUNCTIONS
+
+ # Test if environment is too big by running 'true'
+ # shellcheck disable=SC2006,SC2092
+ if `_which_PAR true` >/dev/null 2>/dev/null ; then
+ parallel "$@"
+ _parallel_exit_CODE=$?
+ # Clean up variables/functions
+ unset PARALLEL_ENV
+ unset _which_PAR _which_TRUE
+ unset _warning_PAR _error_PAR
+ # Unset _parallel_exit_CODE before return
+ eval "unset _parallel_exit_CODE; return $_parallel_exit_CODE"
+ else
+ unset PARALLEL_ENV;
+ _error_PAR "Your environment is too big."
+ _error_PAR "You can try 3 different approaches:"
+ _error_PAR "1. Run 'env_parallel --session' before you set"
+ _error_PAR " variables or define functions."
+ _error_PAR "2. Use --env and only mention the names to copy."
+ _error_PAR "3. Try running this in a clean environment once:"
+ _error_PAR " env_parallel --record-env"
+ _error_PAR " And then use '--env _'"
+ _error_PAR "For details see: man env_parallel"
+ return 255
+ fi
+}
+
+parset() {
+ _parset_PARALLEL_PRG=parallel
+ _parset_main "$@"
+}
+
+env_parset() {
+ _parset_PARALLEL_PRG=env_parallel
+ _parset_main "$@"
+}
+
+_parset_main() {
+ # If $1 contains ',' or space:
+ # Split on , to get the destination variable names
+ # If $1 is a single destination variable name:
+ # Treat it as the name of an array
+ #
+ # # Create array named myvar
+ # parset myvar echo ::: {1..10}
+ # echo ${myvar[5]}
+ #
+ # # Put output into $var_a $var_b $var_c
+ # varnames=(var_a var_b var_c)
+ # parset "${varnames[*]}" echo ::: {1..3}
+ # echo $var_c
+ #
+ # # Put output into $var_a4 $var_b4 $var_c4
+ # parset "var_a4 var_b4 var_c4" echo ::: {1..3}
+ # echo $var_c4
+
+ _parset_NAME="$1"
+ if [ "$_parset_NAME" = "" ] ; then
+ echo parset: Error: No destination variable given. >&2
+ echo parset: Error: Try: >&2
+ echo parset: Error: ' ' parset myarray echo ::: foo bar >&2
+ return 255
+ fi
+ if [ "$_parset_NAME" = "--help" ] ; then
+ echo parset: Error: Usage: >&2
+ echo parset: Error: ' ' parset varname GNU Parallel options and command >&2
+ echo
+ parallel --help
+ return 255
+ fi
+ if [ "$_parset_NAME" = "--version" ] ; then
+ # shellcheck disable=SC2006
+ echo "parset 20240222 (GNU parallel `parallel --minversion 1`)"
+ echo "Copyright (C) 2007-2024 Ole Tange, http://ole.tange.dk and Free Software"
+ echo "Foundation, Inc."
+ echo "License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>"
+ echo "This is free software: you are free to change and redistribute it."
+ echo "GNU parallel comes with no warranty."
+ echo
+ echo "Web site: https://www.gnu.org/software/parallel"
+ echo
+ echo "When using programs that use GNU Parallel to process data for publication"
+ echo "please cite as described in 'parallel --citation'."
+ echo
+ return 255
+ fi
+ shift
+
+ # Bash: declare -A myassoc=( )
+ # Zsh: typeset -A myassoc=( )
+ # Ksh: typeset -A myassoc=( )
+ # shellcheck disable=SC2039,SC2169,SC3044
+ if (typeset -p "$_parset_NAME" 2>/dev/null; echo) |
+ perl -ne 'exit not (/^declare[^=]+-A|^typeset[^=]+-A/)' ; then
+ # This is an associative array
+ # shellcheck disable=SC2006
+ eval "`$_parset_PARALLEL_PRG -k --_parset assoc,"$_parset_NAME" "$@"`"
+ # The eval returns the function!
+ else
+ # This is a normal array or a list of variable names
+ # shellcheck disable=SC2006
+ eval "`$_parset_PARALLEL_PRG -k --_parset var,"$_parset_NAME" "$@"`"
+ # The eval returns the function!
+ fi
+}
diff --git a/src/env_parallel.bash b/src/env_parallel.bash
new file mode 100755
index 0000000..6869d79
--- /dev/null
+++ b/src/env_parallel.bash
@@ -0,0 +1,640 @@
+#!/usr/bin/env bash
+
+# This file must be sourced in sh/ash/dash/bash/ksh/mksh/zsh:
+#
+# . env_parallel.sh
+# source env_parallel.ash
+# source env_parallel.dash
+# source env_parallel.bash
+# source env_parallel.ksh
+# source env_parallel.mksh
+# source env_parallel.zsh
+#
+# after which 'env_parallel' works
+#
+#
+# Copyright (C) 2016-2024 Ole Tange, http://ole.tange.dk and 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/>
+# or write to the Free Software Foundation, Inc., 51 Franklin St,
+# Fifth Floor, Boston, MA 02110-1301 USA
+#
+# SPDX-FileCopyrightText: 2021-2024 Ole Tange, http://ole.tange.dk and Free Software and Foundation, Inc.
+# SPDX-License-Identifier: GPL-3.0-or-later
+# shellcheck disable=SC2006
+
+env_parallel() {
+ # env_parallel.{sh,ash,dash,bash,ksh,mksh,zsh}
+
+ # Check shell dialect
+ if [ -n "$BASH_VERSION" ]; then
+ _shell_DIALECT=bash
+ _eval_needed=false
+ _prefix_PARALLEL_ENV=_prefix_PARALLEL_ENV_bash
+ elif [ -n "$ZSH_VERSION" ]; then
+ _shell_DIALECT=zsh
+ _eval_needed=true
+ _prefix_PARALLEL_ENV=false
+ elif [ -n "$KSH_VERSION" ]; then
+ _shell_DIALECT=ksh
+ _eval_needed=false
+ _prefix_PARALLEL_ENV=false
+ else
+ # Dash/ash - can these be detected better?
+ _shell_DIALECT="sh"
+ _eval_needed=false
+ _prefix_PARALLEL_ENV=false
+ fi
+ _names_of_ALIASES() {
+ _names_of_ALIASES_$_shell_DIALECT
+ }
+ _names_of_ALIASES_sh() {
+ # alias fails on Unixware 5
+ for _i in `alias 2>/dev/null | perl -ne 's/^alias //;s/^(\S+)=.*/$1/ && print' 2>/dev/null`; do
+ # Check if this name really is an alias
+ # or just part of a multiline alias definition
+ if alias "$_i" >/dev/null 2>/dev/null; then
+ echo "$_i"
+ fi
+ done
+ }
+ _names_of_ALIASES_bash() {
+ # No aliases will return false. This error should be ignored.
+ # shellcheck disable=SC3044
+ compgen -a || true
+ }
+ _names_of_ALIASES_ksh() {
+ alias | perl -pe 's/=.*//'
+ }
+ _names_of_ALIASES_zsh() {
+ # shellcheck disable=SC2086,SC2296
+ print -l ${(k)aliases}
+ }
+ _bodies_of_ALIASES() {
+ _bodies_of_ALIASES_$_shell_DIALECT "$@"
+ }
+ _bodies_of_ALIASES_sh() {
+ # alias may return:
+ # myalias='definition' (GNU/Linux ash)
+ # alias myalias='definition' (FreeBSD ash)
+ # so remove 'alias ' from first line
+ for _i in "$@"; do
+ echo 'alias '"`alias "$_i" | perl -pe '1..1 and s/^alias //'`"
+ done
+ }
+ _bodies_of_ALIASES_bash() {
+ # shellcheck disable=SC3043
+ local _i
+ for _i in "$@"; do
+ # shellcheck disable=SC2046
+ if [ $(alias "$_i" | wc -l) = 1 ] ; then
+ true Alias is a single line. Good.
+ else
+ _warning_PAR "Alias '$_i' contains newline."
+ _warning_PAR "Make sure the command has at least one newline after '$_i'."
+ _warning_PAR "See BUGS in 'man env_parallel'."
+ fi
+ done
+ alias "$@"
+ }
+ _bodies_of_ALIASES_ksh() {
+ alias "$@" | perl -pe 's/^/alias /;
+ sub warning { print STDERR "env_parallel: Warning: @_\n"; }
+ if(/^alias (\S+)=\$.*\\n/) {
+ warning("Alias \"$1\" contains newline.");
+ warning("Make sure the command has at least one newline after \"$1\".");
+ warning("See BUGS in \"man env_parallel\".");
+ }'
+
+ }
+ _bodies_of_ALIASES_zsh() {
+ # shellcheck disable=SC3043
+ local _i
+ for _i in "$@"; do
+ echo 'alias '"$(alias "$_i")"
+ done
+ }
+ _names_of_FUNCTIONS() {
+ _names_of_FUNCTIONS_$_shell_DIALECT
+ }
+ _names_of_FUNCTIONS_bash() {
+ # shellcheck disable=SC3044
+ compgen -A function
+ }
+ _names_of_maybe_FUNCTIONS() {
+ set | perl -ne '/^([A-Z_0-9]+)\s*\(\)\s*\{?$/i and print "$1\n"'
+ }
+ _names_of_FUNCTIONS_sh() {
+ # myfunc is a function
+ # shellcheck disable=SC2046
+ LANG=C type `_names_of_maybe_FUNCTIONS` |
+ perl -ne '/^(\S+) is a function$/ and not $seen{$1}++ and print "$1\n"'
+ }
+ _names_of_FUNCTIONS_ksh() {
+ # shellcheck disable=SC3044
+ typeset +f | perl -pe 's/\(\).*//; s/ .*//;'
+ }
+ _names_of_FUNCTIONS_zsh() {
+ # shellcheck disable=SC2086,SC2296
+ print -l ${(k)functions}
+ }
+ _bodies_of_FUNCTIONS() {
+ _bodies_of_FUNCTIONS_$_shell_DIALECT "$@"
+ }
+ _bodies_of_FUNCTIONS_sh() {
+ LANG=C type "$@" | perl -ne '/^(\S+) is a function$/ or print'
+ }
+ _bodies_of_FUNCTIONS_bash() {
+ # shellcheck disable=SC3044
+ typeset -f "$@"
+ }
+ _bodies_of_FUNCTIONS_ksh() {
+ functions "$@"
+ }
+ _bodies_of_FUNCTIONS_zsh() {
+ # shellcheck disable=SC3044
+ typeset -f "$@"
+ }
+ _names_of_VARIABLES() {
+ _names_of_VARIABLES_$_shell_DIALECT
+ }
+ _names_of_VARIABLES_sh() {
+ # This may screw up if variables contain \n and =
+ set | perl -ne 's/^(\S+?)=.*/$1/ and print;'
+ }
+ _names_of_VARIABLES_bash() {
+ # shellcheck disable=SC3044
+ compgen -A variable
+ }
+ _names_of_VARIABLES_ksh() {
+ # mksh: typeset +p |
+ # perl -pe 's/^(type)?set( [-+][a-zA-Z0-9]*)* //; s/(\[\d+\])?=.*//' |
+ # uniq
+ # ksh: typeset +p | perl -pe 's/^typeset .. //'
+ # shellcheck disable=SC3044
+ typeset +p |
+ perl -pe 's/^(type)?set( [-+][a-zA-Z0-9]*)* //; s/(\[\d+\])?=.*//' |
+ uniq
+ }
+ _names_of_VARIABLES_zsh() {
+ # shellcheck disable=SC2086,SC2296
+ print -l ${(k)parameters}
+ }
+ _bodies_of_VARIABLES() {
+ _bodies_of_VARIABLES_$_shell_DIALECT "$@"
+ }
+ _bodies_of_VARIABLES_sh() {
+ # Crappy typeset -p
+ for _i in "$@"
+ do
+ perl -e 'print @ARGV' "$_i="
+ eval echo "\"\$$_i\"" | perl -e '$/=undef; $a=<>; chop($a); print $a' |
+ perl -pe 's/[\002-\011\013-\032\\\#\?\`\(\)\{\}\[\]\^\*\<\=\>\~\|\; \"\!\$\&\202-\377]/\\$&/go;'"s/'/\\\'/g; s/[\n]/'\\n'/go;";
+ echo
+ done
+ }
+ _bodies_of_VARIABLES_bash() {
+ # shellcheck disable=SC3044
+ typeset -p "$@"
+ }
+ _bodies_of_VARIABLES_ksh() {
+ # shellcheck disable=SC3044
+ typeset -p "$@"
+ }
+ _bodies_of_VARIABLES_zsh() {
+ # shellcheck disable=SC3044
+ typeset -p "$@"
+ }
+ _ignore_HARDCODED() {
+ _ignore_HARDCODED_$_shell_DIALECT
+ }
+ _ignore_HARDCODED_sh() {
+ # These names cannot be detected
+ echo '(_|TIMEOUT|IFS)'
+ }
+ _ignore_HARDCODED_bash() {
+ # Copying $RANDOM will cause it not to be random
+ # The rest cannot be detected as read-only
+ echo '(RANDOM|_|TIMEOUT|GROUPS|FUNCNAME|DIRSTACK|PIPESTATUS|USERNAME|BASHPID|BASH_[A-Z_]+)'
+ }
+ _ignore_HARDCODED_ksh() {
+ # These names cannot be detected
+ echo '(_|TIMEOUT|IFS)'
+ }
+ _ignore_HARDCODED_zsh() {
+ # These names cannot be detected
+ echo '([-\?\#\!\$\*\@\_0]|zsh_eval_context|ZSH_EVAL_CONTEXT|LINENO|IFS|commands|functions|options|aliases|EUID|EGID|UID|GID|dis_patchars|patchars|terminfo|galiases|keymaps|parameters|jobdirs|dirstack|functrace|funcsourcetrace|zsh_scheduled_events|dis_aliases|dis_reswords|dis_saliases|modules|reswords|saliases|widgets|userdirs|historywords|nameddirs|termcap|dis_builtins|dis_functions|jobtexts|funcfiletrace|dis_galiases|builtins|history|jobstates|funcstack|run-help)'
+ }
+ _ignore_READONLY() {
+ _ignore_READONLY_$_shell_DIALECT
+ }
+ _parse_READONLY() {
+ # shellcheck disable=SC1078,SC1079,SC2026
+ perl -e '@r = map {
+ chomp;
+ # sh on UnixWare: readonly TIMEOUT
+ # ash: readonly var='val'
+ # ksh: var='val'
+ # mksh: PIPESTATUS[0]
+ s/^(readonly )?([^=\[ ]*?)(\[\d+\])?(=.*|)$/$2/ or
+ # bash: declare -ar BASH_VERSINFO=([0]="4" [1]="4")
+ # zsh: typeset -r var='val'
+ s/^\S+\s+\S+\s+(\S[^=]*)(=.*|$)/$1/;
+ $_ } <>;
+ $vars = join "|",map { quotemeta $_ } @r;
+ print $vars ? "($vars)" : "(,,nO,,VaRs,,)";
+ '
+ }
+ _ignore_READONLY_sh() {
+ readonly | _parse_READONLY
+ }
+ _ignore_READONLY_bash() {
+ readonly | _parse_READONLY
+ }
+ _ignore_READONLY_ksh() {
+ readonly | _parse_READONLY
+ }
+ _ignore_READONLY_zsh() {
+ # shellcheck disable=SC3044
+ typeset -pr | _parse_READONLY
+ }
+ _remove_bad_NAMES() {
+ # Do not transfer vars and funcs from env_parallel
+ # shellcheck disable=SC2006
+ _ignore_RO="`_ignore_READONLY`"
+ # shellcheck disable=SC2006
+ _ignore_HARD="`_ignore_HARDCODED`"
+ # To avoid depending on grep dialect, use Perl version of:
+ # grep -Ev '^(...)$' |
+ perl -ne '/^(
+ PARALLEL_ENV|
+ PARALLEL_TMP|
+ _alias_NAMES|
+ _bodies_of_ALIASES|
+ _bodies_of_FUNCTIONS|
+ _bodies_of_VARIABLES|
+ _error_PAR|
+ _function_NAMES|
+ _get_ignored_VARS|
+ _grep_REGEXP|
+ _ignore_HARD|
+ _ignore_HARDCODED|
+ _ignore_READONLY|
+ _ignore_RO|
+ _ignore_UNDERSCORE|
+ _list_alias_BODIES|
+ _list_function_BODIES|
+ _list_variable_VALUES|
+ _make_grep_REGEXP|
+ _names_of_ALIASES|
+ _names_of_FUNCTIONS|
+ _names_of_VARIABLES|
+ _names_of_maybe_FUNCTIONS|
+ _parallel_exit_CODE|
+ _prefix_PARALLEL_ENV|
+ _prefix_PARALLEL_ENV_bash|
+ _remove_bad_NAMES|
+ _remove_readonly|
+ _variable_NAMES|
+ _warning_PAR|
+ _which_PAR)$/x and next;
+ # Filter names matching --env
+ /^'"$_grep_REGEXP"'$/ or next;
+ /^'"$_ignore_UNDERSCORE"'$/ and next;
+ # Remove readonly variables
+ /^'"$_ignore_RO"'$/ and next;
+ /^'"$_ignore_HARD"'$/ and next;
+ print;'
+ }
+ _prefix_PARALLEL_ENV_bash() {
+ # shellcheck disable=SC3044
+ shopt 2>/dev/null |
+ perl -pe 's:\s+off:;: and s/^/shopt -u /;
+ s:\s+on:;: and s/^/shopt -s /;
+ s:;$:&>/dev/null;:';
+ echo 'shopt -s expand_aliases &>/dev/null';
+ }
+
+ _get_ignored_VARS() {
+ perl -e '
+ for(@ARGV){
+ $next_is_env and push @envvar, split/,/, $_;
+ $next_is_env=/^--env$/;
+ }
+ if(grep { /^_$/ } @envvar) {
+ if(not open(IN, "<", "$ENV{HOME}/.parallel/ignored_vars")) {
+ print STDERR "parallel: Error: ",
+ "Run \"parallel --record-env\" in a clean environment first.\n";
+ } else {
+ chomp(@ignored_vars = <IN>);
+ }
+ }
+ if($ENV{PARALLEL_IGNORED_NAMES}) {
+ push @ignored_vars, split/\s+/, $ENV{PARALLEL_IGNORED_NAMES};
+ chomp @ignored_vars;
+ }
+ $vars = join "|",map { quotemeta $_ } @ignored_vars;
+ print $vars ? "($vars)" : "(,,nO,,VaRs,,)";
+ ' -- "$@"
+ }
+
+ # Get the --env variables if set
+ # --env _ should be ignored
+ # and convert a b c to (a|b|c)
+ # If --env not set: Match everything (.*)
+ _make_grep_REGEXP() {
+ perl -e '
+ for(@ARGV){
+ /^_$/ and $next_is_env = 0;
+ $next_is_env and push @envvar, split/,/, $_;
+ $next_is_env = /^--env$/;
+ }
+ $vars = join "|",map { quotemeta $_ } @envvar;
+ print $vars ? "($vars)" : "(.*)";
+ ' -- "$@"
+ }
+ _which_PAR() {
+ # type returns:
+ # ll is an alias for ls -l (in ash)
+ # bash is a tracked alias for /bin/bash
+ # true is a shell builtin (in bash)
+ # myfunc is a function (in bash)
+ # myfunc is a shell function (in zsh)
+ # which is /usr/bin/which (in sh, bash)
+ # which is hashed (/usr/bin/which)
+ # gi is aliased to `grep -i' (in bash)
+ # aliased to `alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
+ # Return 0 if found, 1 otherwise
+ LANG=C type "$@" |
+ perl -pe '$exit += (s/ is an alias for .*// ||
+ s/ is aliased to .*// ||
+ s/ is a function// ||
+ s/ is a shell function// ||
+ s/ is a shell builtin// ||
+ s/.* is hashed .(\S+).$/$1/ ||
+ s/.* is (a tracked alias for )?//);
+ END { exit not $exit }'
+ }
+ _warning_PAR() {
+ echo "env_parallel: Warning: $*" >&2
+ }
+ _error_PAR() {
+ echo "env_parallel: Error: $*" >&2
+ }
+
+ if _which_PAR parallel >/dev/null; then
+ true parallel found in path
+ else
+ # shellcheck disable=SC2016
+ _error_PAR 'parallel must be in $PATH.'
+ return 255
+ fi
+
+ # Grep regexp for vars given by --env
+ # shellcheck disable=SC2006
+ _grep_REGEXP="`_make_grep_REGEXP \"$@\"`"
+ unset _make_grep_REGEXP
+
+ # Deal with --env _
+ # shellcheck disable=SC2006
+ _ignore_UNDERSCORE="`_get_ignored_VARS \"$@\"`"
+ unset _get_ignored_VARS
+
+ # --record-env
+ if perl -e 'exit grep { /^--record-env$/ } @ARGV' -- "$@"; then
+ true skip
+ else
+ (_names_of_ALIASES;
+ _names_of_FUNCTIONS;
+ _names_of_VARIABLES) |
+ cat > "$HOME"/.parallel/ignored_vars
+ return 0
+ fi
+
+ # --session
+ if perl -e 'exit grep { /^--session$/ } @ARGV' -- "$@"; then
+ true skip
+ else
+ # Insert ::: between each level of session
+ # so you can pop off the last ::: at --end-session
+ # shellcheck disable=SC2006
+ PARALLEL_IGNORED_NAMES="`echo \"$PARALLEL_IGNORED_NAMES\";
+ echo :::;
+ (_names_of_ALIASES;
+ _names_of_FUNCTIONS;
+ _names_of_VARIABLES) | perl -ne '
+ BEGIN{
+ map { $ignored_vars{$_}++ }
+ split/\s+/, $ENV{PARALLEL_IGNORED_NAMES};
+ }
+ chomp;
+ for(split/\s+/) {
+ if(not $ignored_vars{$_}) {
+ print $_,\"\\n\";
+ }
+ }
+ '`"
+ export PARALLEL_IGNORED_NAMES
+ return 0
+ fi
+ if perl -e 'exit grep { /^--end.?session$/ } @ARGV' -- "$@"; then
+ true skip
+ else
+ # Pop off last ::: from PARALLEL_IGNORED_NAMES
+ # shellcheck disable=SC2006
+ PARALLEL_IGNORED_NAMES="`perl -e '
+ $ENV{PARALLEL_IGNORED_NAMES} =~ s/(.*):::.*?$/$1/s;
+ print $ENV{PARALLEL_IGNORED_NAMES}
+ '`"
+ return 0
+ fi
+ # Grep alias names
+ # shellcheck disable=SC2006
+ _alias_NAMES="`_names_of_ALIASES | _remove_bad_NAMES | xargs echo`"
+ _list_alias_BODIES="_bodies_of_ALIASES $_alias_NAMES"
+ if [ "$_alias_NAMES" = "" ] ; then
+ # no aliases selected
+ _list_alias_BODIES="true"
+ fi
+ unset _alias_NAMES
+
+ # Grep function names
+ # shellcheck disable=SC2006
+ _function_NAMES="`_names_of_FUNCTIONS | _remove_bad_NAMES | xargs echo`"
+ _list_function_BODIES="_bodies_of_FUNCTIONS $_function_NAMES"
+ if [ "$_function_NAMES" = "" ] ; then
+ # no functions selected
+ _list_function_BODIES="true"
+ fi
+ unset _function_NAMES
+
+ # Grep variable names
+ # shellcheck disable=SC2006
+ _variable_NAMES="`_names_of_VARIABLES | _remove_bad_NAMES | xargs echo`"
+ _list_variable_VALUES="_bodies_of_VARIABLES $_variable_NAMES"
+ if [ "$_variable_NAMES" = "" ] ; then
+ # no variables selected
+ _list_variable_VALUES="true"
+ fi
+ unset _variable_NAMES
+
+ if $_eval_needed ; then
+ # shellcheck disable=SC2006
+ PARALLEL_ENV="`
+ eval $_prefix_PARALLEL_ENV;
+ eval $_list_alias_BODIES;
+ eval $_list_function_BODIES;
+ eval $_list_variable_VALUES;
+ `"
+ else
+ # shellcheck disable=SC2006
+ PARALLEL_ENV="`
+ $_prefix_PARALLEL_ENV;
+ $_list_alias_BODIES;
+ $_list_function_BODIES;
+ $_list_variable_VALUES;
+ `"
+ fi
+ export PARALLEL_ENV
+ # Free up some env space
+ unset _list_alias_BODIES _list_variable_VALUES _list_function_BODIES
+ unset _bodies_of_ALIASES _bodies_of_VARIABLES _bodies_of_FUNCTIONS
+ unset _names_of_ALIASES _names_of_VARIABLES _names_of_FUNCTIONS
+ unset _ignore_HARDCODED _ignore_READONLY _ignore_UNDERSCORE
+ unset _remove_bad_NAMES _grep_REGEXP _parse_READONLY
+ unset _prefix_PARALLEL_ENV
+ unset _ignore_READONLY_sh _ignore_READONLY_bash
+ unset _ignore_READONLY_ksh _ignore_READONLY_zsh
+ unset _ignore_HARDCODED_sh _ignore_HARDCODED_bash
+ unset _ignore_HARDCODED_ksh _ignore_HARDCODED_zsh
+ unset _bodies_of_ALIASES_ksh _bodies_of_ALIASES_sh
+ unset _bodies_of_ALIASES_zsh _bodies_of_FUNCTIONS_bash
+ unset _bodies_of_FUNCTIONS_ksh _bodies_of_FUNCTIONS_sh
+ unset _bodies_of_FUNCTIONS_zsh _bodies_of_VARIABLES_bash
+ unset _bodies_of_VARIABLES_ksh _bodies_of_VARIABLES_sh
+ unset _bodies_of_VARIABLES_zsh
+ unset _names_of_ALIASES _names_of_ALIASES_bash
+ unset _names_of_ALIASES_ksh _names_of_ALIASES_sh
+ unset _names_of_ALIASES_zsh _names_of_FUNCTIONS
+ unset _names_of_FUNCTIONS_bash _names_of_FUNCTIONS_ksh
+ unset _names_of_FUNCTIONS_sh _names_of_FUNCTIONS_zsh
+ unset _names_of_VARIABLES _names_of_VARIABLES_bash
+ unset _names_of_VARIABLES_ksh _names_of_VARIABLES_sh
+ unset _names_of_VARIABLES_zsh _names_of_maybe_FUNCTIONS
+
+ # Test if environment is too big by running 'true'
+ # shellcheck disable=SC2006,SC2092
+ if `_which_PAR true` >/dev/null 2>/dev/null ; then
+ parallel "$@"
+ _parallel_exit_CODE=$?
+ # Clean up variables/functions
+ unset PARALLEL_ENV
+ unset _which_PAR _which_TRUE
+ unset _warning_PAR _error_PAR
+ # Unset _parallel_exit_CODE before return
+ eval "unset _parallel_exit_CODE; return $_parallel_exit_CODE"
+ else
+ unset PARALLEL_ENV;
+ _error_PAR "Your environment is too big."
+ _error_PAR "You can try 3 different approaches:"
+ _error_PAR "1. Run 'env_parallel --session' before you set"
+ _error_PAR " variables or define functions."
+ _error_PAR "2. Use --env and only mention the names to copy."
+ _error_PAR "3. Try running this in a clean environment once:"
+ _error_PAR " env_parallel --record-env"
+ _error_PAR " And then use '--env _'"
+ _error_PAR "For details see: man env_parallel"
+ return 255
+ fi
+}
+
+parset() {
+ _parset_PARALLEL_PRG=parallel
+ _parset_main "$@"
+}
+
+env_parset() {
+ _parset_PARALLEL_PRG=env_parallel
+ _parset_main "$@"
+}
+
+_parset_main() {
+ # If $1 contains ',' or space:
+ # Split on , to get the destination variable names
+ # If $1 is a single destination variable name:
+ # Treat it as the name of an array
+ #
+ # # Create array named myvar
+ # parset myvar echo ::: {1..10}
+ # echo ${myvar[5]}
+ #
+ # # Put output into $var_a $var_b $var_c
+ # varnames=(var_a var_b var_c)
+ # parset "${varnames[*]}" echo ::: {1..3}
+ # echo $var_c
+ #
+ # # Put output into $var_a4 $var_b4 $var_c4
+ # parset "var_a4 var_b4 var_c4" echo ::: {1..3}
+ # echo $var_c4
+
+ _parset_NAME="$1"
+ if [ "$_parset_NAME" = "" ] ; then
+ echo parset: Error: No destination variable given. >&2
+ echo parset: Error: Try: >&2
+ echo parset: Error: ' ' parset myarray echo ::: foo bar >&2
+ return 255
+ fi
+ if [ "$_parset_NAME" = "--help" ] ; then
+ echo parset: Error: Usage: >&2
+ echo parset: Error: ' ' parset varname GNU Parallel options and command >&2
+ echo
+ parallel --help
+ return 255
+ fi
+ if [ "$_parset_NAME" = "--version" ] ; then
+ # shellcheck disable=SC2006
+ echo "parset 20240222 (GNU parallel `parallel --minversion 1`)"
+ echo "Copyright (C) 2007-2024 Ole Tange, http://ole.tange.dk and Free Software"
+ echo "Foundation, Inc."
+ echo "License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>"
+ echo "This is free software: you are free to change and redistribute it."
+ echo "GNU parallel comes with no warranty."
+ echo
+ echo "Web site: https://www.gnu.org/software/parallel"
+ echo
+ echo "When using programs that use GNU Parallel to process data for publication"
+ echo "please cite as described in 'parallel --citation'."
+ echo
+ return 255
+ fi
+ shift
+
+ # Bash: declare -A myassoc=( )
+ # Zsh: typeset -A myassoc=( )
+ # Ksh: typeset -A myassoc=( )
+ # shellcheck disable=SC2039,SC2169,SC3044
+ if (typeset -p "$_parset_NAME" 2>/dev/null; echo) |
+ perl -ne 'exit not (/^declare[^=]+-A|^typeset[^=]+-A/)' ; then
+ # This is an associative array
+ # shellcheck disable=SC2006
+ eval "`$_parset_PARALLEL_PRG -k --_parset assoc,"$_parset_NAME" "$@"`"
+ # The eval returns the function!
+ else
+ # This is a normal array or a list of variable names
+ # shellcheck disable=SC2006
+ eval "`$_parset_PARALLEL_PRG -k --_parset var,"$_parset_NAME" "$@"`"
+ # The eval returns the function!
+ fi
+}
diff --git a/src/env_parallel.csh b/src/env_parallel.csh
new file mode 100755
index 0000000..3f00e3a
--- /dev/null
+++ b/src/env_parallel.csh
@@ -0,0 +1,142 @@
+#!/usr/bin/env csh
+
+# This file must be sourced in csh:
+#
+# source `which env_parallel.csh`
+#
+# after which 'env_parallel' works
+#
+#
+# Copyright (C) 2016-2024 Ole Tange, http://ole.tange.dk and 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/>
+# or write to the Free Software Foundation, Inc., 51 Franklin St,
+# Fifth Floor, Boston, MA 02110-1301 USA
+#
+# SPDX-FileCopyrightText: 2021-2024 Ole Tange, http://ole.tange.dk and Free Software and Foundation, Inc.
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+set _parallel_exit_CODE=0
+if ("`alias env_parallel`" == '' || ! $?PARALLEL_CSH) then
+ # Activate alias
+ alias env_parallel '(setenv PARALLEL_CSH "\!*"; source `which env_parallel.csh`)'
+else
+ # Get the --env variables if set
+ # --env _ should be ignored
+ # and convert a b c to (a|b|c)
+ # If --env not set: Match everything (.*)
+
+ # simple 'tempfile': Return nonexisting filename: /tmp/parXXXXX
+ alias _tempfile 'perl -e do\{\$t\=\"/tmp/par\".join\"\",map\{\(0..9,\"a\"..\"z\",\"A\"..\"Z\"\)\[rand\(62\)\]\}\(1..5\)\;\}while\(-e\$t\)\;print\"\$t\\n\"'
+ set _tMpscRIpt=`_tempfile`
+
+ cat <<'EOF' > $_tMpscRIpt
+ #!/usr/bin/perl
+
+ for(@ARGV){
+ /^_$/ and $next_is_env = 0;
+ $next_is_env and push @envvar, split/,/, $_;
+ $next_is_env = /^--env$/;
+ }
+ $vars = join "|",map { quotemeta $_ } @envvar;
+ print $vars ? "($vars)" : "(.*)";
+'EOF'
+ set _grep_REGEXP="`perl $_tMpscRIpt -- $PARALLEL_CSH`"
+
+ # Deal with --env _
+ cat <<'EOF' > $_tMpscRIpt
+ #!/usr/bin/perl
+
+ for(@ARGV){
+ $next_is_env and push @envvar, split/,/, $_;
+ $next_is_env=/^--env$/;
+ }
+ if(grep { /^_$/ } @envvar) {
+ if(not open(IN, "<", "$ENV{HOME}/.parallel/ignored_vars")) {
+ print STDERR "parallel: Error: ",
+ "Run \"parallel --record-env\" in a clean environment first.\n";
+ } else {
+ chomp(@ignored_vars = <IN>);
+ $vars = join "|",map { quotemeta $_ } @ignored_vars;
+ print $vars ? "($vars)" : "(,,nO,,VaRs,,)";
+ }
+ }
+'EOF'
+ set _ignore_UNDERSCORE="`perl $_tMpscRIpt -- $PARALLEL_CSH`"
+ rm $_tMpscRIpt
+
+ # Get the scalar and array variable names
+ set _vARnAmES=(`set | perl -ne 's/\s.*//; /^(#|_|killring|prompt2|command|PARALLEL_ENV|PARALLEL_TMP)$/ and next; /^'"$_grep_REGEXP"'$/ or next; /^'"$_ignore_UNDERSCORE"'$/ and next; print'`)
+
+ # Make a tmpfile for the variable definitions
+ set _tMpvARfILe=`_tempfile`
+ touch $_tMpvARfILe
+ # Make a tmpfile for the variable definitions + alias
+ set _tMpaLLfILe=`_tempfile`
+ foreach _vARnAmE ($_vARnAmES);
+ # These 3 lines break in csh ver. 20110502-3
+ # if not defined: next
+ eval if'(! $?'$_vARnAmE') continue'
+ # if $#myvar <= 1 echo scalar_myvar=$var
+ eval if'(${#'$_vARnAmE'} <= 1) echo scalar_'$_vARnAmE'='\"\$$_vARnAmE\" >> $_tMpvARfILe;
+ # if $#myvar > 1 echo array_myvar=$var
+ eval if'(${#'$_vARnAmE'} > 1) echo array_'$_vARnAmE'="$'$_vARnAmE'"' >> $_tMpvARfILe;
+ end
+ unset _vARnAmE _vARnAmES
+ # shell quote variables (--plain needed due to ignore if $PARALLEL is set)
+ # Convert 'scalar_myvar=...' to 'set myvar=...'
+ # Convert 'array_myvar=...' to 'set array=(...)'
+ cat $_tMpvARfILe | parallel --plain --shellquote | perl -pe 's/^scalar_(\S+).=/set $1=/ or s/^array_(\S+).=(.*)/set $1=($2)/ && s/\\ / /g;' > $_tMpaLLfILe
+ # Cleanup
+ rm $_tMpvARfILe; unset _tMpvARfILe
+
+# ALIAS TO EXPORT ALIASES:
+
+# Quote ' by putting it inside "
+# s/'/'"'"'/g;
+# ' => \047 " => \042
+# s/\047/\047\042\047\042\047/g;
+# Quoted: s/\\047/\\047\\042\\047\\042\\047/g\;
+
+# Remove () from second column
+# s/^(\S+)(\s+)\((.*)\)/\1\2\3/;
+# Quoted: s/\^\(\\S+\)\(\\s+\)\\\(\(.\*\)\\\)/\\1\\2\\3/\;
+
+# Add ' around second column
+# s/^(\S+)(\s+)(.*)/\1\2'\3'/
+# \047 => '
+# s/^(\S+)(\s+)(.*)/\1\2\047\3\047/;
+# Quoted: s/\^\(\\S+\)\(\\s+\)\(.\*\)/\\1\\2\\047\\3\\047/\;
+
+# Quote ! as \!
+# s/\!/\\\!/g;
+# Quoted: s/\\\!/\\\\\\\!/g;
+
+# Prepend with "\nalias "
+# s/^/\001alias /;
+# Quoted: s/\^/\\001alias\ /\;
+ alias | \
+ perl -ne '/^'"$_grep_REGEXP"'/ or next; /^'"$_ignore_UNDERSCORE"'[^_a-zA-Z]/ and next; print' | \
+ perl -pe s/\\047/\\047\\042\\047\\042\\047/g\;s/\^\(\\S+\)\(\\s+\)\\\(\(.\*\)\\\)/\\1\\2\\3/\;s/\^\(\\S+\)\(\\s+\)\(.\*\)/\\1\\2\\047\\3\\047/\;s/\^/\\001alias\ /\;s/\\\!/\\\\\\\!/g >> $_tMpaLLfILe
+
+ setenv PARALLEL_ENV "`cat $_tMpaLLfILe; rm $_tMpaLLfILe`";
+ unset _tMpaLLfILe;
+ # Use $PARALLEL_CSH set in calling alias
+ parallel
+ set _parallel_exit_CODE=$status
+ setenv PARALLEL_ENV
+ setenv PARALLEL_CSH
+endif
+(exit $_parallel_exit_CODE)
diff --git a/src/env_parallel.dash b/src/env_parallel.dash
new file mode 100755
index 0000000..0d09760
--- /dev/null
+++ b/src/env_parallel.dash
@@ -0,0 +1,636 @@
+#!/usr/bin/env dash
+
+# This file must be sourced in sh/ash/dash/bash/ksh/mksh/zsh:
+#
+# . env_parallel.sh
+# source env_parallel.ash
+# source env_parallel.dash
+# source env_parallel.bash
+# source env_parallel.ksh
+# source env_parallel.mksh
+# source env_parallel.zsh
+#
+# after which 'env_parallel' works
+#
+#
+# Copyright (C) 2016-2024 Ole Tange, http://ole.tange.dk and 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/>
+# or write to the Free Software Foundation, Inc., 51 Franklin St,
+# Fifth Floor, Boston, MA 02110-1301 USA
+#
+# SPDX-FileCopyrightText: 2021-2024 Ole Tange, http://ole.tange.dk and Free Software and Foundation, Inc.
+# SPDX-License-Identifier: GPL-3.0-or-later
+# shellcheck disable=SC2006
+
+env_parallel() {
+ # env_parallel.{sh,ash,dash,bash,ksh,mksh,zsh}
+
+ # Check shell dialect
+ if [ -n "$BASH_VERSION" ]; then
+ _shell_DIALECT=bash
+ _eval_needed=false
+ _prefix_PARALLEL_ENV=_prefix_PARALLEL_ENV_bash
+ elif [ -n "$ZSH_VERSION" ]; then
+ _shell_DIALECT=zsh
+ _eval_needed=true
+ _prefix_PARALLEL_ENV=false
+ elif [ -n "$KSH_VERSION" ]; then
+ _shell_DIALECT=ksh
+ _eval_needed=false
+ _prefix_PARALLEL_ENV=false
+ else
+ # Dash/ash - can these be detected better?
+ _shell_DIALECT="sh"
+ _eval_needed=false
+ _prefix_PARALLEL_ENV=false
+ fi
+ _names_of_ALIASES() {
+ _names_of_ALIASES_$_shell_DIALECT
+ }
+ _names_of_ALIASES_sh() {
+ # alias fails on Unixware 5
+ for _i in `alias 2>/dev/null | perl -ne 's/^alias //;s/^(\S+)=.*/$1/ && print' 2>/dev/null`; do
+ # Check if this name really is an alias
+ # or just part of a multiline alias definition
+ if alias "$_i" >/dev/null 2>/dev/null; then
+ echo "$_i"
+ fi
+ done
+ }
+ _names_of_ALIASES_bash() {
+ # No aliases will return false. This error should be ignored.
+ # shellcheck disable=SC3044
+ compgen -a || true
+ }
+ _names_of_ALIASES_ksh() {
+ alias | perl -pe 's/=.*//'
+ }
+ _names_of_ALIASES_zsh() {
+ # shellcheck disable=SC2086,SC2296
+ print -l ${(k)aliases}
+ }
+ _bodies_of_ALIASES() {
+ _bodies_of_ALIASES_$_shell_DIALECT "$@"
+ }
+ _bodies_of_ALIASES_sh() {
+ # alias may return:
+ # myalias='definition' (GNU/Linux ash)
+ # alias myalias='definition' (FreeBSD ash)
+ # so remove 'alias ' from first line
+ for _i in "$@"; do
+ echo 'alias '"`alias "$_i" | perl -pe '1..1 and s/^alias //'`"
+ done
+ }
+ _bodies_of_ALIASES_bash() {
+ # shellcheck disable=SC3043
+ local _i
+ for _i in "$@"; do
+ # shellcheck disable=SC2046
+ if [ $(alias "$_i" | wc -l) = 1 ] ; then
+ true Alias is a single line. Good.
+ else
+ _warning_PAR "Alias '$_i' contains newline."
+ _warning_PAR "Make sure the command has at least one newline after '$_i'."
+ _warning_PAR "See BUGS in 'man env_parallel'."
+ fi
+ done
+ alias "$@"
+ }
+ _bodies_of_ALIASES_ksh() {
+ alias "$@" | perl -pe 's/^/alias /;
+ sub warning { print STDERR "env_parallel: Warning: @_\n"; }
+ if(/^alias (\S+)=\$.*\\n/) {
+ warning("Alias \"$1\" contains newline.");
+ warning("Make sure the command has at least one newline after \"$1\".");
+ warning("See BUGS in \"man env_parallel\".");
+ }'
+
+ }
+ _bodies_of_ALIASES_zsh() {
+ # shellcheck disable=SC3043
+ local _i
+ for _i in "$@"; do
+ echo 'alias '"$(alias "$_i")"
+ done
+ }
+ _names_of_FUNCTIONS() {
+ _names_of_FUNCTIONS_$_shell_DIALECT
+ }
+ _names_of_FUNCTIONS_bash() {
+ # shellcheck disable=SC3044
+ compgen -A function
+ }
+ _names_of_maybe_FUNCTIONS() {
+ set | perl -ne '/^([A-Z_0-9]+)\s*\(\)\s*\{?$/i and print "$1\n"'
+ }
+ _names_of_FUNCTIONS_sh() {
+ # myfunc is a function
+ # shellcheck disable=SC2046
+ LANG=C type `_names_of_maybe_FUNCTIONS` |
+ perl -ne '/^(\S+) is a function$/ and not $seen{$1}++ and print "$1\n"'
+ }
+ _names_of_FUNCTIONS_ksh() {
+ # shellcheck disable=SC3044
+ typeset +f | perl -pe 's/\(\).*//; s/ .*//;'
+ }
+ _names_of_FUNCTIONS_zsh() {
+ # shellcheck disable=SC2086,SC2296
+ print -l ${(k)functions}
+ }
+ _bodies_of_FUNCTIONS() {
+ _bodies_of_FUNCTIONS_$_shell_DIALECT "$@"
+ }
+ _bodies_of_FUNCTIONS_sh() {
+ LANG=C type "$@" | perl -ne '/^(\S+) is a function$/ or print'
+ }
+ _bodies_of_FUNCTIONS_bash() {
+ # shellcheck disable=SC3044
+ typeset -f "$@"
+ }
+ _bodies_of_FUNCTIONS_ksh() {
+ functions "$@"
+ }
+ _bodies_of_FUNCTIONS_zsh() {
+ # shellcheck disable=SC3044
+ typeset -f "$@"
+ }
+ _names_of_VARIABLES() {
+ _names_of_VARIABLES_$_shell_DIALECT
+ }
+ _names_of_VARIABLES_sh() {
+ # This may screw up if variables contain \n and =
+ set | perl -ne 's/^(\S+?)=.*/$1/ and print;'
+ }
+ _names_of_VARIABLES_bash() {
+ # shellcheck disable=SC3044
+ compgen -A variable
+ }
+ _names_of_VARIABLES_ksh() {
+ # shellcheck disable=SC3044
+ typeset +p |
+ perl -pe 's/^(type)?set( [-+][a-zA-Z0-9]*)* //; s/(\[\d+\])?=.*//' |
+ uniq
+ }
+ _names_of_VARIABLES_zsh() {
+ # shellcheck disable=SC2086,SC2296
+ print -l ${(k)parameters}
+ }
+ _bodies_of_VARIABLES() {
+ _bodies_of_VARIABLES_$_shell_DIALECT "$@"
+ }
+ _bodies_of_VARIABLES_sh() {
+ # Crappy typeset -p
+ for _i in "$@"
+ do
+ perl -e 'print @ARGV' "$_i="
+ eval echo "\"\$$_i\"" | perl -e '$/=undef; $a=<>; chop($a); print $a' |
+ perl -pe 's/[\002-\011\013-\032\\\#\?\`\(\)\{\}\[\]\^\*\<\=\>\~\|\; \"\!\$\&\202-\377]/\\$&/go;'"s/'/\\\'/g; s/[\n]/'\\n'/go;";
+ echo
+ done
+ }
+ _bodies_of_VARIABLES_bash() {
+ # shellcheck disable=SC3044
+ typeset -p "$@"
+ }
+ _bodies_of_VARIABLES_ksh() {
+ # shellcheck disable=SC3044
+ typeset -p "$@"
+ }
+ _bodies_of_VARIABLES_zsh() {
+ # shellcheck disable=SC3044
+ typeset -p "$@"
+ }
+ _ignore_HARDCODED() {
+ _ignore_HARDCODED_$_shell_DIALECT
+ }
+ _ignore_HARDCODED_sh() {
+ # These names cannot be detected
+ echo '(_|TIMEOUT|IFS)'
+ }
+ _ignore_HARDCODED_bash() {
+ # Copying $RANDOM will cause it not to be random
+ # The rest cannot be detected as read-only
+ echo '(RANDOM|_|TIMEOUT|GROUPS|FUNCNAME|DIRSTACK|PIPESTATUS|USERNAME|BASHPID|BASH_[A-Z_]+)'
+ }
+ _ignore_HARDCODED_ksh() {
+ # These names cannot be detected
+ echo '(_|TIMEOUT|IFS)'
+ }
+ _ignore_HARDCODED_zsh() {
+ # These names cannot be detected
+ echo '([-\?\#\!\$\*\@\_0]|zsh_eval_context|ZSH_EVAL_CONTEXT|LINENO|IFS|commands|functions|options|aliases|EUID|EGID|UID|GID|dis_patchars|patchars|terminfo|galiases|keymaps|parameters|jobdirs|dirstack|functrace|funcsourcetrace|zsh_scheduled_events|dis_aliases|dis_reswords|dis_saliases|modules|reswords|saliases|widgets|userdirs|historywords|nameddirs|termcap|dis_builtins|dis_functions|jobtexts|funcfiletrace|dis_galiases|builtins|history|jobstates|funcstack|run-help)'
+ }
+ _ignore_READONLY() {
+ _ignore_READONLY_$_shell_DIALECT
+ }
+ _parse_READONLY() {
+ # shellcheck disable=SC1078,SC1079,SC2026
+ perl -e '@r = map {
+ chomp;
+ # sh on UnixWare: readonly TIMEOUT
+ # ash: readonly var='val'
+ # ksh: var='val'
+ # mksh: PIPESTATUS[0]
+ s/^(readonly )?([^=\[ ]*?)(\[\d+\])?(=.*|)$/$2/ or
+ # bash: declare -ar BASH_VERSINFO=([0]="4" [1]="4")
+ # zsh: typeset -r var='val'
+ s/^\S+\s+\S+\s+(\S[^=]*)(=.*|$)/$1/;
+ $_ } <>;
+ $vars = join "|",map { quotemeta $_ } @r;
+ print $vars ? "($vars)" : "(,,nO,,VaRs,,)";
+ '
+ }
+ _ignore_READONLY_sh() {
+ readonly | _parse_READONLY
+ }
+ _ignore_READONLY_bash() {
+ readonly | _parse_READONLY
+ }
+ _ignore_READONLY_ksh() {
+ readonly | _parse_READONLY
+ }
+ _ignore_READONLY_zsh() {
+ # shellcheck disable=SC3044
+ typeset -pr | _parse_READONLY
+ }
+ _remove_bad_NAMES() {
+ # Do not transfer vars and funcs from env_parallel
+ # shellcheck disable=SC2006
+ _ignore_RO="`_ignore_READONLY`"
+ # shellcheck disable=SC2006
+ _ignore_HARD="`_ignore_HARDCODED`"
+ # To avoid depending on grep dialect, use Perl version of:
+ # grep -Ev '^(...)$' |
+ perl -ne '/^(
+ PARALLEL_ENV|
+ PARALLEL_TMP|
+ _alias_NAMES|
+ _bodies_of_ALIASES|
+ _bodies_of_FUNCTIONS|
+ _bodies_of_VARIABLES|
+ _error_PAR|
+ _function_NAMES|
+ _get_ignored_VARS|
+ _grep_REGEXP|
+ _ignore_HARD|
+ _ignore_HARDCODED|
+ _ignore_READONLY|
+ _ignore_RO|
+ _ignore_UNDERSCORE|
+ _list_alias_BODIES|
+ _list_function_BODIES|
+ _list_variable_VALUES|
+ _make_grep_REGEXP|
+ _names_of_ALIASES|
+ _names_of_FUNCTIONS|
+ _names_of_VARIABLES|
+ _names_of_maybe_FUNCTIONS|
+ _parallel_exit_CODE|
+ _prefix_PARALLEL_ENV|
+ _prefix_PARALLEL_ENV_bash|
+ _remove_bad_NAMES|
+ _remove_readonly|
+ _variable_NAMES|
+ _warning_PAR|
+ _which_PAR)$/x and next;
+ # Filter names matching --env
+ /^'"$_grep_REGEXP"'$/ or next;
+ /^'"$_ignore_UNDERSCORE"'$/ and next;
+ # Remove readonly variables
+ /^'"$_ignore_RO"'$/ and next;
+ /^'"$_ignore_HARD"'$/ and next;
+ print;'
+ }
+ _prefix_PARALLEL_ENV_bash() {
+ # shellcheck disable=SC3044
+ shopt 2>/dev/null |
+ perl -pe 's:\s+off:;: and s/^/shopt -u /;
+ s:\s+on:;: and s/^/shopt -s /;
+ s:;$:&>/dev/null;:';
+ echo 'shopt -s expand_aliases &>/dev/null';
+ }
+
+ _get_ignored_VARS() {
+ perl -e '
+ for(@ARGV){
+ $next_is_env and push @envvar, split/,/, $_;
+ $next_is_env=/^--env$/;
+ }
+ if(grep { /^_$/ } @envvar) {
+ if(not open(IN, "<", "$ENV{HOME}/.parallel/ignored_vars")) {
+ print STDERR "parallel: Error: ",
+ "Run \"parallel --record-env\" in a clean environment first.\n";
+ } else {
+ chomp(@ignored_vars = <IN>);
+ }
+ }
+ if($ENV{PARALLEL_IGNORED_NAMES}) {
+ push @ignored_vars, split/\s+/, $ENV{PARALLEL_IGNORED_NAMES};
+ chomp @ignored_vars;
+ }
+ $vars = join "|",map { quotemeta $_ } @ignored_vars;
+ print $vars ? "($vars)" : "(,,nO,,VaRs,,)";
+ ' -- "$@"
+ }
+
+ # Get the --env variables if set
+ # --env _ should be ignored
+ # and convert a b c to (a|b|c)
+ # If --env not set: Match everything (.*)
+ _make_grep_REGEXP() {
+ perl -e '
+ for(@ARGV){
+ /^_$/ and $next_is_env = 0;
+ $next_is_env and push @envvar, split/,/, $_;
+ $next_is_env = /^--env$/;
+ }
+ $vars = join "|",map { quotemeta $_ } @envvar;
+ print $vars ? "($vars)" : "(.*)";
+ ' -- "$@"
+ }
+ _which_PAR() {
+ # type returns:
+ # ll is an alias for ls -l (in ash)
+ # bash is a tracked alias for /bin/bash
+ # true is a shell builtin (in bash)
+ # myfunc is a function (in bash)
+ # myfunc is a shell function (in zsh)
+ # which is /usr/bin/which (in sh, bash)
+ # which is hashed (/usr/bin/which)
+ # gi is aliased to `grep -i' (in bash)
+ # aliased to `alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
+ # Return 0 if found, 1 otherwise
+ LANG=C type "$@" |
+ perl -pe '$exit += (s/ is an alias for .*// ||
+ s/ is aliased to .*// ||
+ s/ is a function// ||
+ s/ is a shell function// ||
+ s/ is a shell builtin// ||
+ s/.* is hashed .(\S+).$/$1/ ||
+ s/.* is (a tracked alias for )?//);
+ END { exit not $exit }'
+ }
+ _warning_PAR() {
+ echo "env_parallel: Warning: $*" >&2
+ }
+ _error_PAR() {
+ echo "env_parallel: Error: $*" >&2
+ }
+
+ if _which_PAR parallel >/dev/null; then
+ true parallel found in path
+ else
+ # shellcheck disable=SC2016
+ _error_PAR 'parallel must be in $PATH.'
+ return 255
+ fi
+
+ # Grep regexp for vars given by --env
+ # shellcheck disable=SC2006
+ _grep_REGEXP="`_make_grep_REGEXP \"$@\"`"
+ unset _make_grep_REGEXP
+
+ # Deal with --env _
+ # shellcheck disable=SC2006
+ _ignore_UNDERSCORE="`_get_ignored_VARS \"$@\"`"
+ unset _get_ignored_VARS
+
+ # --record-env
+ if perl -e 'exit grep { /^--record-env$/ } @ARGV' -- "$@"; then
+ true skip
+ else
+ (_names_of_ALIASES;
+ _names_of_FUNCTIONS;
+ _names_of_VARIABLES) |
+ cat > "$HOME"/.parallel/ignored_vars
+ return 0
+ fi
+
+ # --session
+ if perl -e 'exit grep { /^--session$/ } @ARGV' -- "$@"; then
+ true skip
+ else
+ # Insert ::: between each level of session
+ # so you can pop off the last ::: at --end-session
+ # shellcheck disable=SC2006
+ PARALLEL_IGNORED_NAMES="`echo \"$PARALLEL_IGNORED_NAMES\";
+ echo :::;
+ (_names_of_ALIASES;
+ _names_of_FUNCTIONS;
+ _names_of_VARIABLES) | perl -ne '
+ BEGIN{
+ map { $ignored_vars{$_}++ }
+ split/\s+/, $ENV{PARALLEL_IGNORED_NAMES};
+ }
+ chomp;
+ for(split/\s+/) {
+ if(not $ignored_vars{$_}) {
+ print $_,\"\\n\";
+ }
+ }
+ '`"
+ export PARALLEL_IGNORED_NAMES
+ return 0
+ fi
+ if perl -e 'exit grep { /^--end.?session$/ } @ARGV' -- "$@"; then
+ true skip
+ else
+ # Pop off last ::: from PARALLEL_IGNORED_NAMES
+ # shellcheck disable=SC2006
+ PARALLEL_IGNORED_NAMES="`perl -e '
+ $ENV{PARALLEL_IGNORED_NAMES} =~ s/(.*):::.*?$/$1/s;
+ print $ENV{PARALLEL_IGNORED_NAMES}
+ '`"
+ return 0
+ fi
+ # Grep alias names
+ # shellcheck disable=SC2006
+ _alias_NAMES="`_names_of_ALIASES | _remove_bad_NAMES | xargs echo`"
+ _list_alias_BODIES="_bodies_of_ALIASES $_alias_NAMES"
+ if [ "$_alias_NAMES" = "" ] ; then
+ # no aliases selected
+ _list_alias_BODIES="true"
+ fi
+ unset _alias_NAMES
+
+ # Grep function names
+ # shellcheck disable=SC2006
+ _function_NAMES="`_names_of_FUNCTIONS | _remove_bad_NAMES | xargs echo`"
+ _list_function_BODIES="_bodies_of_FUNCTIONS $_function_NAMES"
+ if [ "$_function_NAMES" = "" ] ; then
+ # no functions selected
+ _list_function_BODIES="true"
+ fi
+ unset _function_NAMES
+
+ # Grep variable names
+ # shellcheck disable=SC2006
+ _variable_NAMES="`_names_of_VARIABLES | _remove_bad_NAMES | xargs echo`"
+ _list_variable_VALUES="_bodies_of_VARIABLES $_variable_NAMES"
+ if [ "$_variable_NAMES" = "" ] ; then
+ # no variables selected
+ _list_variable_VALUES="true"
+ fi
+ unset _variable_NAMES
+
+ if $_eval_needed ; then
+ # shellcheck disable=SC2006
+ PARALLEL_ENV="`
+ eval $_prefix_PARALLEL_ENV;
+ eval $_list_alias_BODIES;
+ eval $_list_function_BODIES;
+ eval $_list_variable_VALUES;
+ `"
+ else
+ # shellcheck disable=SC2006
+ PARALLEL_ENV="`
+ $_prefix_PARALLEL_ENV;
+ $_list_alias_BODIES;
+ $_list_function_BODIES;
+ $_list_variable_VALUES;
+ `"
+ fi
+ export PARALLEL_ENV
+ # Free up some env space
+ unset _list_alias_BODIES _list_variable_VALUES _list_function_BODIES
+ unset _bodies_of_ALIASES _bodies_of_VARIABLES _bodies_of_FUNCTIONS
+ unset _names_of_ALIASES _names_of_VARIABLES _names_of_FUNCTIONS
+ unset _ignore_HARDCODED _ignore_READONLY _ignore_UNDERSCORE
+ unset _remove_bad_NAMES _grep_REGEXP _parse_READONLY
+ unset _prefix_PARALLEL_ENV
+ unset _ignore_READONLY_sh _ignore_READONLY_bash
+ unset _ignore_READONLY_ksh _ignore_READONLY_zsh
+ unset _ignore_HARDCODED_sh _ignore_HARDCODED_bash
+ unset _ignore_HARDCODED_ksh _ignore_HARDCODED_zsh
+ unset _bodies_of_ALIASES_ksh _bodies_of_ALIASES_sh
+ unset _bodies_of_ALIASES_zsh _bodies_of_FUNCTIONS_bash
+ unset _bodies_of_FUNCTIONS_ksh _bodies_of_FUNCTIONS_sh
+ unset _bodies_of_FUNCTIONS_zsh _bodies_of_VARIABLES_bash
+ unset _bodies_of_VARIABLES_ksh _bodies_of_VARIABLES_sh
+ unset _bodies_of_VARIABLES_zsh
+ unset _names_of_ALIASES _names_of_ALIASES_bash
+ unset _names_of_ALIASES_ksh _names_of_ALIASES_sh
+ unset _names_of_ALIASES_zsh _names_of_FUNCTIONS
+ unset _names_of_FUNCTIONS_bash _names_of_FUNCTIONS_ksh
+ unset _names_of_FUNCTIONS_sh _names_of_FUNCTIONS_zsh
+ unset _names_of_VARIABLES _names_of_VARIABLES_bash
+ unset _names_of_VARIABLES_ksh _names_of_VARIABLES_sh
+ unset _names_of_VARIABLES_zsh _names_of_maybe_FUNCTIONS
+
+ # Test if environment is too big by running 'true'
+ # shellcheck disable=SC2006,SC2092
+ if `_which_PAR true` >/dev/null 2>/dev/null ; then
+ parallel "$@"
+ _parallel_exit_CODE=$?
+ # Clean up variables/functions
+ unset PARALLEL_ENV
+ unset _which_PAR _which_TRUE
+ unset _warning_PAR _error_PAR
+ # Unset _parallel_exit_CODE before return
+ eval "unset _parallel_exit_CODE; return $_parallel_exit_CODE"
+ else
+ unset PARALLEL_ENV;
+ _error_PAR "Your environment is too big."
+ _error_PAR "You can try 3 different approaches:"
+ _error_PAR "1. Run 'env_parallel --session' before you set"
+ _error_PAR " variables or define functions."
+ _error_PAR "2. Use --env and only mention the names to copy."
+ _error_PAR "3. Try running this in a clean environment once:"
+ _error_PAR " env_parallel --record-env"
+ _error_PAR " And then use '--env _'"
+ _error_PAR "For details see: man env_parallel"
+ return 255
+ fi
+}
+
+parset() {
+ _parset_PARALLEL_PRG=parallel
+ _parset_main "$@"
+}
+
+env_parset() {
+ _parset_PARALLEL_PRG=env_parallel
+ _parset_main "$@"
+}
+
+_parset_main() {
+ # If $1 contains ',' or space:
+ # Split on , to get the destination variable names
+ # If $1 is a single destination variable name:
+ # Treat it as the name of an array
+ #
+ # # Create array named myvar
+ # parset myvar echo ::: {1..10}
+ # echo ${myvar[5]}
+ #
+ # # Put output into $var_a $var_b $var_c
+ # varnames=(var_a var_b var_c)
+ # parset "${varnames[*]}" echo ::: {1..3}
+ # echo $var_c
+ #
+ # # Put output into $var_a4 $var_b4 $var_c4
+ # parset "var_a4 var_b4 var_c4" echo ::: {1..3}
+ # echo $var_c4
+
+ _parset_NAME="$1"
+ if [ "$_parset_NAME" = "" ] ; then
+ echo parset: Error: No destination variable given. >&2
+ echo parset: Error: Try: >&2
+ echo parset: Error: ' ' parset myarray echo ::: foo bar >&2
+ return 255
+ fi
+ if [ "$_parset_NAME" = "--help" ] ; then
+ echo parset: Error: Usage: >&2
+ echo parset: Error: ' ' parset varname GNU Parallel options and command >&2
+ echo
+ parallel --help
+ return 255
+ fi
+ if [ "$_parset_NAME" = "--version" ] ; then
+ # shellcheck disable=SC2006
+ echo "parset 20240222 (GNU parallel `parallel --minversion 1`)"
+ echo "Copyright (C) 2007-2024 Ole Tange, http://ole.tange.dk and Free Software"
+ echo "Foundation, Inc."
+ echo "License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>"
+ echo "This is free software: you are free to change and redistribute it."
+ echo "GNU parallel comes with no warranty."
+ echo
+ echo "Web site: https://www.gnu.org/software/parallel"
+ echo
+ echo "When using programs that use GNU Parallel to process data for publication"
+ echo "please cite as described in 'parallel --citation'."
+ echo
+ return 255
+ fi
+ shift
+
+ # Bash: declare -A myassoc=( )
+ # Zsh: typeset -A myassoc=( )
+ # Ksh: typeset -A myassoc=( )
+ # shellcheck disable=SC2039,SC2169,SC3044
+ if (typeset -p "$_parset_NAME" 2>/dev/null; echo) |
+ perl -ne 'exit not (/^declare[^=]+-A|^typeset[^=]+-A/)' ; then
+ # This is an associative array
+ # shellcheck disable=SC2006
+ eval "`$_parset_PARALLEL_PRG -k --_parset assoc,"$_parset_NAME" "$@"`"
+ # The eval returns the function!
+ else
+ # This is a normal array or a list of variable names
+ # shellcheck disable=SC2006
+ eval "`$_parset_PARALLEL_PRG -k --_parset var,"$_parset_NAME" "$@"`"
+ # The eval returns the function!
+ fi
+}
diff --git a/src/env_parallel.fish b/src/env_parallel.fish
new file mode 100755
index 0000000..b0abc50
--- /dev/null
+++ b/src/env_parallel.fish
@@ -0,0 +1,194 @@
+#!/usr/bin/env fish
+
+# This file must be sourced in fish:
+#
+# . (which env_parallel.fish)
+#
+# after which 'env_parallel' works
+#
+#
+# Copyright (C) 2016-2024 Ole Tange, http://ole.tange.dk and 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/>
+# or write to the Free Software Foundation, Inc., 51 Franklin St,
+# Fifth Floor, Boston, MA 02110-1301 USA
+#
+# SPDX-FileCopyrightText: 2021-2024 Ole Tange, http://ole.tange.dk and Free Software and Foundation, Inc.
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+# If you are a fisherman feel free to improve the code
+#
+# The code needs to deal with variables like:
+# set funky (perl -e 'print pack "c*", 2..254')
+#
+# Problem:
+# Tell the difference between:
+# set tmp "a' 'b' 'c"
+# set tmparr1 "a' 'b" 'c'
+# set tmparr2 'a' "b' 'c"
+# The output from `set` is exactly the same.
+# Solution:
+# for-loop for each variable. Each value is separated with a
+# separator.
+
+function env_parallel
+ # env_parallel.fish
+
+ # --session
+ perl -e 'exit grep { /^--session/ } @ARGV' -- $argv; or begin;
+ setenv PARALLEL_IGNORED_NAMES (
+ begin;
+ functions -n
+ set -n;
+ end | perl -pe 's/\n/,/g';
+ )
+ return 0
+ end;
+ setenv PARALLEL_ENV (
+ begin;
+ set _grep_REGEXP (
+ begin;
+ perl -e '
+ for(@ARGV){
+ /^_$/ and $next_is_env = 0;
+ $next_is_env and push @envvar, split/,/, $_;
+ $next_is_env = /^--env$/;
+ }
+ $vars = join "|",map { quotemeta $_ } @envvar;
+ print $vars ? "($vars)" : "(.*)";
+ ' -- $argv;
+ end;
+ )
+ # Deal with --env _
+ set _ignore_UNDERSCORE (
+ begin;
+ perl -e '
+ for(@ARGV){
+ $next_is_env and push @envvar, split/,/, $_;
+ $next_is_env=/^--env$/;
+ }
+ if(grep { /^_$/ } @envvar) {
+ if(not open(IN, "<", "$ENV{HOME}/.parallel/ignored_vars")) {
+ print STDERR "parallel: Error: ",
+ "Run \"parallel --record-env\" in a clean environment first.\n";
+ } else {
+ chomp(@ignored_vars = <IN>);
+ }
+ }
+ if($ENV{PARALLEL_IGNORED_NAMES}) {
+ push @ignored_vars, split/,/, $ENV{PARALLEL_IGNORED_NAMES};
+ chomp @ignored_vars;
+ }
+ $vars = join "|",map { quotemeta $_ } @ignored_vars;
+ print $vars ? "($vars)" : "(,,nO,,VaRs,,)";
+ ' -- $argv;
+ end;
+ )
+
+ # --record-env
+ perl -e 'exit grep { /^--record-env$/ } @ARGV' -- $argv; or begin;
+ begin;
+ functions -n | perl -pe 's/,/\n/g';
+ set -n;
+ end | cat > $HOME/.parallel/ignored_vars;
+ end;
+
+ # Export function definitions
+ # Keep the ones from --env
+ # Ignore the ones from ~/.parallel/ignored_vars
+ # Dump each function defition
+ # Replace \001 with \002 because \001 is used by env_parallel
+ # Convert \n to \001
+ functions -n | perl -pe 's/,/\n/g' | \
+ grep -Ev '^(PARALLEL_ENV|PARALLEL_TMP)$' | \
+ grep -E "^$_grep_REGEXP"\$ | grep -vE "^$_ignore_UNDERSCORE"\$ | \
+ while read d; functions $d; end | \
+ perl -pe 's/\001/\002/g and not $printed++ and print STDERR
+ "env_parallel: Warning: ASCII value 1 in functions is not supported\n";
+ s/\n/\001/g';
+ # Convert scalar vars to fish \XX quoting
+ # Keep the ones from --env
+ # Ignore the ones from ~/.parallel/ignored_vars
+ # Ignore read only vars
+ # Execute 'set' of the content
+ eval (set -L | \
+ grep -Ev '^(PARALLEL_TMP)$' | \
+ grep -E "^$_grep_REGEXP " | grep -vE "^$_ignore_UNDERSCORE " | \
+ perl -ne 'chomp;
+ ($name,$val)=split(/ /,$_,2);
+ $name=~/^(HOME|USER|COLUMNS|FISH_VERSION|LINES|PWD|SHLVL|_|
+ history|status|version)$|\./x and next;
+ if($val=~/^'"'"'/) { next; }
+ print "set $name \"\$$name\";\n";
+ ')
+ # Generate commands to set scalar variables
+ # Keep the ones from --env
+ # Ignore the ones from ~/.parallel/ignored_vars
+ #
+ begin;
+ for v in (set -n | \
+ grep -Ev '^(PARALLEL_TMP)$' | \
+ grep -E "^$_grep_REGEXP\$" | grep -vE "^$_ignore_UNDERSCORE\$");
+ # Separate variables with the string: \000
+ # array_name1 val1\0
+ # array_name1 val2\0
+ # array_name2 val3\0
+ # array_name2 val4\0
+ eval "for i in \$$v;
+ echo -n $v \$i;
+ perl -e print\\\"\\\\0\\\";
+ end;"
+ end;
+ # A final line to flush the last variable in Perl
+ perl -e print\"\\0\";
+ end | perl -0 -ne '
+ # Remove separator string \0
+ chop;
+ # Split line into name and value
+ ($name,$val)=split(/ /,$_,2);
+ # Ignore read-only vars
+ $name=~/^(HOME|USER|COLUMNS|FISH_VERSION|LINES|PWD|SHLVL|_|
+ fish_pid|history|hostname|status|version)$/x and next;
+ # Single quote $val
+ if($val =~ /[^-_.+a-z0-9\/]/i) {
+ $val =~ s/\047/\047"\047"\047/g; # "-quote single quotes
+ $val = "\047$val\047"; # single-quote entire string
+ $val =~ s/^\047\047|\047\047$//g; # Remove unneeded '' at ends
+ } elsif ($val eq "") {
+ $val = "\047\047";
+ }
+
+ if($name ne $last and $last) {
+ # The $name is different, so this is a new variable.
+ # Print the last one.
+ # Separate list elements by 2 spaces
+ $"=" ";
+ print "set $last @qval;\n";
+ @qval=();
+ }
+ push @qval,$val;
+ $last=$name;
+ '| \
+ perl -pe 's/\001/\002/g and not $printed++ and print STDERR
+ "env_parallel: Warning: ASCII value 1 in variables is not supported\n";
+ s/\n/\001/g'
+ end;
+ )
+ # If --record-env: exit
+ perl -e 'exit grep { /^--record-env$/ } @ARGV' -- $argv; and parallel $argv;
+ set _parallel_exit_CODE $status
+ set -e PARALLEL_ENV
+ return $_parallel_exit_CODE
+end
diff --git a/src/env_parallel.ksh b/src/env_parallel.ksh
new file mode 100755
index 0000000..bc20d41
--- /dev/null
+++ b/src/env_parallel.ksh
@@ -0,0 +1,636 @@
+#!/usr/bin/env ksh
+
+# This file must be sourced in sh/ash/dash/bash/ksh/mksh/zsh:
+#
+# . env_parallel.sh
+# source env_parallel.ash
+# source env_parallel.dash
+# source env_parallel.bash
+# source env_parallel.ksh
+# source env_parallel.mksh
+# source env_parallel.zsh
+#
+# after which 'env_parallel' works
+#
+#
+# Copyright (C) 2016-2024 Ole Tange, http://ole.tange.dk and 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/>
+# or write to the Free Software Foundation, Inc., 51 Franklin St,
+# Fifth Floor, Boston, MA 02110-1301 USA
+#
+# SPDX-FileCopyrightText: 2021-2024 Ole Tange, http://ole.tange.dk and Free Software and Foundation, Inc.
+# SPDX-License-Identifier: GPL-3.0-or-later
+# shellcheck disable=SC2006
+
+env_parallel() {
+ # env_parallel.{sh,ash,dash,bash,ksh,mksh,zsh}
+
+ # Check shell dialect
+ if [ -n "$BASH_VERSION" ]; then
+ _shell_DIALECT=bash
+ _eval_needed=false
+ _prefix_PARALLEL_ENV=_prefix_PARALLEL_ENV_bash
+ elif [ -n "$ZSH_VERSION" ]; then
+ _shell_DIALECT=zsh
+ _eval_needed=true
+ _prefix_PARALLEL_ENV=false
+ elif [ -n "$KSH_VERSION" ]; then
+ _shell_DIALECT=ksh
+ _eval_needed=false
+ _prefix_PARALLEL_ENV=false
+ else
+ # Dash/ash - can these be detected better?
+ _shell_DIALECT="sh"
+ _eval_needed=false
+ _prefix_PARALLEL_ENV=false
+ fi
+ _names_of_ALIASES() {
+ _names_of_ALIASES_$_shell_DIALECT
+ }
+ _names_of_ALIASES_sh() {
+ # alias fails on Unixware 5
+ for _i in `alias 2>/dev/null | perl -ne 's/^alias //;s/^(\S+)=.*/$1/ && print' 2>/dev/null`; do
+ # Check if this name really is an alias
+ # or just part of a multiline alias definition
+ if alias "$_i" >/dev/null 2>/dev/null; then
+ echo "$_i"
+ fi
+ done
+ }
+ _names_of_ALIASES_bash() {
+ # No aliases will return false. This error should be ignored.
+ # shellcheck disable=SC3044
+ compgen -a || true
+ }
+ _names_of_ALIASES_ksh() {
+ alias | perl -pe 's/=.*//'
+ }
+ _names_of_ALIASES_zsh() {
+ # shellcheck disable=SC2086,SC2296
+ print -l ${(k)aliases}
+ }
+ _bodies_of_ALIASES() {
+ _bodies_of_ALIASES_$_shell_DIALECT "$@"
+ }
+ _bodies_of_ALIASES_sh() {
+ # alias may return:
+ # myalias='definition' (GNU/Linux ash)
+ # alias myalias='definition' (FreeBSD ash)
+ # so remove 'alias ' from first line
+ for _i in "$@"; do
+ echo 'alias '"`alias "$_i" | perl -pe '1..1 and s/^alias //'`"
+ done
+ }
+ _bodies_of_ALIASES_bash() {
+ # shellcheck disable=SC3043
+ local _i
+ for _i in "$@"; do
+ # shellcheck disable=SC2046
+ if [ $(alias "$_i" | wc -l) = 1 ] ; then
+ true Alias is a single line. Good.
+ else
+ _warning_PAR "Alias '$_i' contains newline."
+ _warning_PAR "Make sure the command has at least one newline after '$_i'."
+ _warning_PAR "See BUGS in 'man env_parallel'."
+ fi
+ done
+ alias "$@"
+ }
+ _bodies_of_ALIASES_ksh() {
+ alias "$@" | perl -pe 's/^/alias /;
+ sub warning { print STDERR "env_parallel: Warning: @_\n"; }
+ if(/^alias (\S+)=\$.*\\n/) {
+ warning("Alias \"$1\" contains newline.");
+ warning("Make sure the command has at least one newline after \"$1\".");
+ warning("See BUGS in \"man env_parallel\".");
+ }'
+
+ }
+ _bodies_of_ALIASES_zsh() {
+ # shellcheck disable=SC3043
+ local _i
+ for _i in "$@"; do
+ echo 'alias '"$(alias "$_i")"
+ done
+ }
+ _names_of_FUNCTIONS() {
+ _names_of_FUNCTIONS_$_shell_DIALECT
+ }
+ _names_of_FUNCTIONS_bash() {
+ # shellcheck disable=SC3044
+ compgen -A function
+ }
+ _names_of_maybe_FUNCTIONS() {
+ set | perl -ne '/^([A-Z_0-9]+)\s*\(\)\s*\{?$/i and print "$1\n"'
+ }
+ _names_of_FUNCTIONS_sh() {
+ # myfunc is a function
+ # shellcheck disable=SC2046
+ LANG=C type `_names_of_maybe_FUNCTIONS` |
+ perl -ne '/^(\S+) is a function$/ and not $seen{$1}++ and print "$1\n"'
+ }
+ _names_of_FUNCTIONS_ksh() {
+ # shellcheck disable=SC3044
+ typeset +f | perl -pe 's/\(\).*//; s/ .*//;'
+ }
+ _names_of_FUNCTIONS_zsh() {
+ # shellcheck disable=SC2086,SC2296
+ print -l ${(k)functions}
+ }
+ _bodies_of_FUNCTIONS() {
+ _bodies_of_FUNCTIONS_$_shell_DIALECT "$@"
+ }
+ _bodies_of_FUNCTIONS_sh() {
+ LANG=C type "$@" | perl -ne '/^(\S+) is a function$/ or print'
+ }
+ _bodies_of_FUNCTIONS_bash() {
+ # shellcheck disable=SC3044
+ typeset -f "$@"
+ }
+ _bodies_of_FUNCTIONS_ksh() {
+ functions "$@"
+ }
+ _bodies_of_FUNCTIONS_zsh() {
+ # shellcheck disable=SC3044
+ typeset -f "$@"
+ }
+ _names_of_VARIABLES() {
+ _names_of_VARIABLES_$_shell_DIALECT
+ }
+ _names_of_VARIABLES_sh() {
+ # This may screw up if variables contain \n and =
+ set | perl -ne 's/^(\S+?)=.*/$1/ and print;'
+ }
+ _names_of_VARIABLES_bash() {
+ # shellcheck disable=SC3044
+ compgen -A variable
+ }
+ _names_of_VARIABLES_ksh() {
+ # shellcheck disable=SC3044
+ typeset +p |
+ perl -pe 's/^(type)?set( [-+][a-zA-Z0-9]*)* //; s/(\[\d+\])?=.*//' |
+ uniq
+ }
+ _names_of_VARIABLES_zsh() {
+ # shellcheck disable=SC2086,SC2296
+ print -l ${(k)parameters}
+ }
+ _bodies_of_VARIABLES() {
+ _bodies_of_VARIABLES_$_shell_DIALECT "$@"
+ }
+ _bodies_of_VARIABLES_sh() {
+ # Crappy typeset -p
+ for _i in "$@"
+ do
+ perl -e 'print @ARGV' "$_i="
+ eval echo "\"\$$_i\"" | perl -e '$/=undef; $a=<>; chop($a); print $a' |
+ perl -pe 's/[\002-\011\013-\032\\\#\?\`\(\)\{\}\[\]\^\*\<\=\>\~\|\; \"\!\$\&\202-\377]/\\$&/go;'"s/'/\\\'/g; s/[\n]/'\\n'/go;";
+ echo
+ done
+ }
+ _bodies_of_VARIABLES_bash() {
+ # shellcheck disable=SC3044
+ typeset -p "$@"
+ }
+ _bodies_of_VARIABLES_ksh() {
+ # shellcheck disable=SC3044
+ typeset -p "$@"
+ }
+ _bodies_of_VARIABLES_zsh() {
+ # shellcheck disable=SC3044
+ typeset -p "$@"
+ }
+ _ignore_HARDCODED() {
+ _ignore_HARDCODED_$_shell_DIALECT
+ }
+ _ignore_HARDCODED_sh() {
+ # These names cannot be detected
+ echo '(_|TIMEOUT|IFS)'
+ }
+ _ignore_HARDCODED_bash() {
+ # Copying $RANDOM will cause it not to be random
+ # The rest cannot be detected as read-only
+ echo '(RANDOM|_|TIMEOUT|GROUPS|FUNCNAME|DIRSTACK|PIPESTATUS|USERNAME|BASHPID|BASH_[A-Z_]+)'
+ }
+ _ignore_HARDCODED_ksh() {
+ # These names cannot be detected
+ echo '(_|TIMEOUT|IFS)'
+ }
+ _ignore_HARDCODED_zsh() {
+ # These names cannot be detected
+ echo '([-\?\#\!\$\*\@\_0]|zsh_eval_context|ZSH_EVAL_CONTEXT|LINENO|IFS|commands|functions|options|aliases|EUID|EGID|UID|GID|dis_patchars|patchars|terminfo|galiases|keymaps|parameters|jobdirs|dirstack|functrace|funcsourcetrace|zsh_scheduled_events|dis_aliases|dis_reswords|dis_saliases|modules|reswords|saliases|widgets|userdirs|historywords|nameddirs|termcap|dis_builtins|dis_functions|jobtexts|funcfiletrace|dis_galiases|builtins|history|jobstates|funcstack|run-help)'
+ }
+ _ignore_READONLY() {
+ _ignore_READONLY_$_shell_DIALECT
+ }
+ _parse_READONLY() {
+ # shellcheck disable=SC1078,SC1079,SC2026
+ perl -e '@r = map {
+ chomp;
+ # sh on UnixWare: readonly TIMEOUT
+ # ash: readonly var='val'
+ # ksh: var='val'
+ # mksh: PIPESTATUS[0]
+ s/^(readonly )?([^=\[ ]*?)(\[\d+\])?(=.*|)$/$2/ or
+ # bash: declare -ar BASH_VERSINFO=([0]="4" [1]="4")
+ # zsh: typeset -r var='val'
+ s/^\S+\s+\S+\s+(\S[^=]*)(=.*|$)/$1/;
+ $_ } <>;
+ $vars = join "|",map { quotemeta $_ } @r;
+ print $vars ? "($vars)" : "(,,nO,,VaRs,,)";
+ '
+ }
+ _ignore_READONLY_sh() {
+ readonly | _parse_READONLY
+ }
+ _ignore_READONLY_bash() {
+ readonly | _parse_READONLY
+ }
+ _ignore_READONLY_ksh() {
+ readonly | _parse_READONLY
+ }
+ _ignore_READONLY_zsh() {
+ # shellcheck disable=SC3044
+ typeset -pr | _parse_READONLY
+ }
+ _remove_bad_NAMES() {
+ # Do not transfer vars and funcs from env_parallel
+ # shellcheck disable=SC2006
+ _ignore_RO="`_ignore_READONLY`"
+ # shellcheck disable=SC2006
+ _ignore_HARD="`_ignore_HARDCODED`"
+ # To avoid depending on grep dialect, use Perl version of:
+ # grep -Ev '^(...)$' |
+ perl -ne '/^(
+ PARALLEL_ENV|
+ PARALLEL_TMP|
+ _alias_NAMES|
+ _bodies_of_ALIASES|
+ _bodies_of_FUNCTIONS|
+ _bodies_of_VARIABLES|
+ _error_PAR|
+ _function_NAMES|
+ _get_ignored_VARS|
+ _grep_REGEXP|
+ _ignore_HARD|
+ _ignore_HARDCODED|
+ _ignore_READONLY|
+ _ignore_RO|
+ _ignore_UNDERSCORE|
+ _list_alias_BODIES|
+ _list_function_BODIES|
+ _list_variable_VALUES|
+ _make_grep_REGEXP|
+ _names_of_ALIASES|
+ _names_of_FUNCTIONS|
+ _names_of_VARIABLES|
+ _names_of_maybe_FUNCTIONS|
+ _parallel_exit_CODE|
+ _prefix_PARALLEL_ENV|
+ _prefix_PARALLEL_ENV_bash|
+ _remove_bad_NAMES|
+ _remove_readonly|
+ _variable_NAMES|
+ _warning_PAR|
+ _which_PAR)$/x and next;
+ # Filter names matching --env
+ /^'"$_grep_REGEXP"'$/ or next;
+ /^'"$_ignore_UNDERSCORE"'$/ and next;
+ # Remove readonly variables
+ /^'"$_ignore_RO"'$/ and next;
+ /^'"$_ignore_HARD"'$/ and next;
+ print;'
+ }
+ _prefix_PARALLEL_ENV_bash() {
+ # shellcheck disable=SC3044
+ shopt 2>/dev/null |
+ perl -pe 's:\s+off:;: and s/^/shopt -u /;
+ s:\s+on:;: and s/^/shopt -s /;
+ s:;$:&>/dev/null;:';
+ echo 'shopt -s expand_aliases &>/dev/null';
+ }
+
+ _get_ignored_VARS() {
+ perl -e '
+ for(@ARGV){
+ $next_is_env and push @envvar, split/,/, $_;
+ $next_is_env=/^--env$/;
+ }
+ if(grep { /^_$/ } @envvar) {
+ if(not open(IN, "<", "$ENV{HOME}/.parallel/ignored_vars")) {
+ print STDERR "parallel: Error: ",
+ "Run \"parallel --record-env\" in a clean environment first.\n";
+ } else {
+ chomp(@ignored_vars = <IN>);
+ }
+ }
+ if($ENV{PARALLEL_IGNORED_NAMES}) {
+ push @ignored_vars, split/\s+/, $ENV{PARALLEL_IGNORED_NAMES};
+ chomp @ignored_vars;
+ }
+ $vars = join "|",map { quotemeta $_ } @ignored_vars;
+ print $vars ? "($vars)" : "(,,nO,,VaRs,,)";
+ ' -- "$@"
+ }
+
+ # Get the --env variables if set
+ # --env _ should be ignored
+ # and convert a b c to (a|b|c)
+ # If --env not set: Match everything (.*)
+ _make_grep_REGEXP() {
+ perl -e '
+ for(@ARGV){
+ /^_$/ and $next_is_env = 0;
+ $next_is_env and push @envvar, split/,/, $_;
+ $next_is_env = /^--env$/;
+ }
+ $vars = join "|",map { quotemeta $_ } @envvar;
+ print $vars ? "($vars)" : "(.*)";
+ ' -- "$@"
+ }
+ _which_PAR() {
+ # type returns:
+ # ll is an alias for ls -l (in ash)
+ # bash is a tracked alias for /bin/bash
+ # true is a shell builtin (in bash)
+ # myfunc is a function (in bash)
+ # myfunc is a shell function (in zsh)
+ # which is /usr/bin/which (in sh, bash)
+ # which is hashed (/usr/bin/which)
+ # gi is aliased to `grep -i' (in bash)
+ # aliased to `alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
+ # Return 0 if found, 1 otherwise
+ LANG=C type "$@" |
+ perl -pe '$exit += (s/ is an alias for .*// ||
+ s/ is aliased to .*// ||
+ s/ is a function// ||
+ s/ is a shell function// ||
+ s/ is a shell builtin// ||
+ s/.* is hashed .(\S+).$/$1/ ||
+ s/.* is (a tracked alias for )?//);
+ END { exit not $exit }'
+ }
+ _warning_PAR() {
+ echo "env_parallel: Warning: $*" >&2
+ }
+ _error_PAR() {
+ echo "env_parallel: Error: $*" >&2
+ }
+
+ if _which_PAR parallel >/dev/null; then
+ true parallel found in path
+ else
+ # shellcheck disable=SC2016
+ _error_PAR 'parallel must be in $PATH.'
+ return 255
+ fi
+
+ # Grep regexp for vars given by --env
+ # shellcheck disable=SC2006
+ _grep_REGEXP="`_make_grep_REGEXP \"$@\"`"
+ unset _make_grep_REGEXP
+
+ # Deal with --env _
+ # shellcheck disable=SC2006
+ _ignore_UNDERSCORE="`_get_ignored_VARS \"$@\"`"
+ unset _get_ignored_VARS
+
+ # --record-env
+ if perl -e 'exit grep { /^--record-env$/ } @ARGV' -- "$@"; then
+ true skip
+ else
+ (_names_of_ALIASES;
+ _names_of_FUNCTIONS;
+ _names_of_VARIABLES) |
+ cat > "$HOME"/.parallel/ignored_vars
+ return 0
+ fi
+
+ # --session
+ if perl -e 'exit grep { /^--session$/ } @ARGV' -- "$@"; then
+ true skip
+ else
+ # Insert ::: between each level of session
+ # so you can pop off the last ::: at --end-session
+ # shellcheck disable=SC2006
+ PARALLEL_IGNORED_NAMES="`echo \"$PARALLEL_IGNORED_NAMES\";
+ echo :::;
+ (_names_of_ALIASES;
+ _names_of_FUNCTIONS;
+ _names_of_VARIABLES) | perl -ne '
+ BEGIN{
+ map { $ignored_vars{$_}++ }
+ split/\s+/, $ENV{PARALLEL_IGNORED_NAMES};
+ }
+ chomp;
+ for(split/\s+/) {
+ if(not $ignored_vars{$_}) {
+ print $_,\"\\n\";
+ }
+ }
+ '`"
+ export PARALLEL_IGNORED_NAMES
+ return 0
+ fi
+ if perl -e 'exit grep { /^--end.?session$/ } @ARGV' -- "$@"; then
+ true skip
+ else
+ # Pop off last ::: from PARALLEL_IGNORED_NAMES
+ # shellcheck disable=SC2006
+ PARALLEL_IGNORED_NAMES="`perl -e '
+ $ENV{PARALLEL_IGNORED_NAMES} =~ s/(.*):::.*?$/$1/s;
+ print $ENV{PARALLEL_IGNORED_NAMES}
+ '`"
+ return 0
+ fi
+ # Grep alias names
+ # shellcheck disable=SC2006
+ _alias_NAMES="`_names_of_ALIASES | _remove_bad_NAMES | xargs echo`"
+ _list_alias_BODIES="_bodies_of_ALIASES $_alias_NAMES"
+ if [ "$_alias_NAMES" = "" ] ; then
+ # no aliases selected
+ _list_alias_BODIES="true"
+ fi
+ unset _alias_NAMES
+
+ # Grep function names
+ # shellcheck disable=SC2006
+ _function_NAMES="`_names_of_FUNCTIONS | _remove_bad_NAMES | xargs echo`"
+ _list_function_BODIES="_bodies_of_FUNCTIONS $_function_NAMES"
+ if [ "$_function_NAMES" = "" ] ; then
+ # no functions selected
+ _list_function_BODIES="true"
+ fi
+ unset _function_NAMES
+
+ # Grep variable names
+ # shellcheck disable=SC2006
+ _variable_NAMES="`_names_of_VARIABLES | _remove_bad_NAMES | xargs echo`"
+ _list_variable_VALUES="_bodies_of_VARIABLES $_variable_NAMES"
+ if [ "$_variable_NAMES" = "" ] ; then
+ # no variables selected
+ _list_variable_VALUES="true"
+ fi
+ unset _variable_NAMES
+
+ if $_eval_needed ; then
+ # shellcheck disable=SC2006
+ PARALLEL_ENV="`
+ eval $_prefix_PARALLEL_ENV;
+ eval $_list_alias_BODIES;
+ eval $_list_function_BODIES;
+ eval $_list_variable_VALUES;
+ `"
+ else
+ # shellcheck disable=SC2006
+ PARALLEL_ENV="`
+ $_prefix_PARALLEL_ENV;
+ $_list_alias_BODIES;
+ $_list_function_BODIES;
+ $_list_variable_VALUES;
+ `"
+ fi
+ export PARALLEL_ENV
+ # Free up some env space
+ unset _list_alias_BODIES _list_variable_VALUES _list_function_BODIES
+ unset _bodies_of_ALIASES _bodies_of_VARIABLES _bodies_of_FUNCTIONS
+ unset _names_of_ALIASES _names_of_VARIABLES _names_of_FUNCTIONS
+ unset _ignore_HARDCODED _ignore_READONLY _ignore_UNDERSCORE
+ unset _remove_bad_NAMES _grep_REGEXP _parse_READONLY
+ unset _prefix_PARALLEL_ENV
+ unset _ignore_READONLY_sh _ignore_READONLY_bash
+ unset _ignore_READONLY_ksh _ignore_READONLY_zsh
+ unset _ignore_HARDCODED_sh _ignore_HARDCODED_bash
+ unset _ignore_HARDCODED_ksh _ignore_HARDCODED_zsh
+ unset _bodies_of_ALIASES_ksh _bodies_of_ALIASES_sh
+ unset _bodies_of_ALIASES_zsh _bodies_of_FUNCTIONS_bash
+ unset _bodies_of_FUNCTIONS_ksh _bodies_of_FUNCTIONS_sh
+ unset _bodies_of_FUNCTIONS_zsh _bodies_of_VARIABLES_bash
+ unset _bodies_of_VARIABLES_ksh _bodies_of_VARIABLES_sh
+ unset _bodies_of_VARIABLES_zsh
+ unset _names_of_ALIASES _names_of_ALIASES_bash
+ unset _names_of_ALIASES_ksh _names_of_ALIASES_sh
+ unset _names_of_ALIASES_zsh _names_of_FUNCTIONS
+ unset _names_of_FUNCTIONS_bash _names_of_FUNCTIONS_ksh
+ unset _names_of_FUNCTIONS_sh _names_of_FUNCTIONS_zsh
+ unset _names_of_VARIABLES _names_of_VARIABLES_bash
+ unset _names_of_VARIABLES_ksh _names_of_VARIABLES_sh
+ unset _names_of_VARIABLES_zsh _names_of_maybe_FUNCTIONS
+
+ # Test if environment is too big by running 'true'
+ # shellcheck disable=SC2006,SC2092
+ if `_which_PAR true` >/dev/null 2>/dev/null ; then
+ parallel "$@"
+ _parallel_exit_CODE=$?
+ # Clean up variables/functions
+ unset PARALLEL_ENV
+ unset _which_PAR _which_TRUE
+ unset _warning_PAR _error_PAR
+ # Unset _parallel_exit_CODE before return
+ eval "unset _parallel_exit_CODE; return $_parallel_exit_CODE"
+ else
+ unset PARALLEL_ENV;
+ _error_PAR "Your environment is too big."
+ _error_PAR "You can try 3 different approaches:"
+ _error_PAR "1. Run 'env_parallel --session' before you set"
+ _error_PAR " variables or define functions."
+ _error_PAR "2. Use --env and only mention the names to copy."
+ _error_PAR "3. Try running this in a clean environment once:"
+ _error_PAR " env_parallel --record-env"
+ _error_PAR " And then use '--env _'"
+ _error_PAR "For details see: man env_parallel"
+ return 255
+ fi
+}
+
+parset() {
+ _parset_PARALLEL_PRG=parallel
+ _parset_main "$@"
+}
+
+env_parset() {
+ _parset_PARALLEL_PRG=env_parallel
+ _parset_main "$@"
+}
+
+_parset_main() {
+ # If $1 contains ',' or space:
+ # Split on , to get the destination variable names
+ # If $1 is a single destination variable name:
+ # Treat it as the name of an array
+ #
+ # # Create array named myvar
+ # parset myvar echo ::: {1..10}
+ # echo ${myvar[5]}
+ #
+ # # Put output into $var_a $var_b $var_c
+ # varnames=(var_a var_b var_c)
+ # parset "${varnames[*]}" echo ::: {1..3}
+ # echo $var_c
+ #
+ # # Put output into $var_a4 $var_b4 $var_c4
+ # parset "var_a4 var_b4 var_c4" echo ::: {1..3}
+ # echo $var_c4
+
+ _parset_NAME="$1"
+ if [ "$_parset_NAME" = "" ] ; then
+ echo parset: Error: No destination variable given. >&2
+ echo parset: Error: Try: >&2
+ echo parset: Error: ' ' parset myarray echo ::: foo bar >&2
+ return 255
+ fi
+ if [ "$_parset_NAME" = "--help" ] ; then
+ echo parset: Error: Usage: >&2
+ echo parset: Error: ' ' parset varname GNU Parallel options and command >&2
+ echo
+ parallel --help
+ return 255
+ fi
+ if [ "$_parset_NAME" = "--version" ] ; then
+ # shellcheck disable=SC2006
+ echo "parset 20240222 (GNU parallel `parallel --minversion 1`)"
+ echo "Copyright (C) 2007-2024 Ole Tange, http://ole.tange.dk and Free Software"
+ echo "Foundation, Inc."
+ echo "License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>"
+ echo "This is free software: you are free to change and redistribute it."
+ echo "GNU parallel comes with no warranty."
+ echo
+ echo "Web site: https://www.gnu.org/software/parallel"
+ echo
+ echo "When using programs that use GNU Parallel to process data for publication"
+ echo "please cite as described in 'parallel --citation'."
+ echo
+ return 255
+ fi
+ shift
+
+ # Bash: declare -A myassoc=( )
+ # Zsh: typeset -A myassoc=( )
+ # Ksh: typeset -A myassoc=( )
+ # shellcheck disable=SC2039,SC2169,SC3044
+ if (typeset -p "$_parset_NAME" 2>/dev/null; echo) |
+ perl -ne 'exit not (/^declare[^=]+-A|^typeset[^=]+-A/)' ; then
+ # This is an associative array
+ # shellcheck disable=SC2006
+ eval "`$_parset_PARALLEL_PRG -k --_parset assoc,"$_parset_NAME" "$@"`"
+ # The eval returns the function!
+ else
+ # This is a normal array or a list of variable names
+ # shellcheck disable=SC2006
+ eval "`$_parset_PARALLEL_PRG -k --_parset var,"$_parset_NAME" "$@"`"
+ # The eval returns the function!
+ fi
+}
diff --git a/src/env_parallel.mksh b/src/env_parallel.mksh
new file mode 100644
index 0000000..d307128
--- /dev/null
+++ b/src/env_parallel.mksh
@@ -0,0 +1,605 @@
+#!/usr/bin/env ksh
+
+# This file must be sourced in sh/ash/dash/bash/ksh/mksh/zsh:
+#
+# . env_parallel.sh
+# source env_parallel.ash
+# source env_parallel.dash
+# source env_parallel.bash
+# source env_parallel.ksh
+# source env_parallel.mksh
+# source env_parallel.zsh
+#
+# after which 'env_parallel' works
+#
+#
+# Copyright (C) 2016-2024 Ole Tange, http://ole.tange.dk and 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/>
+# or write to the Free Software Foundation, Inc., 51 Franklin St,
+# Fifth Floor, Boston, MA 02110-1301 USA
+#
+# SPDX-FileCopyrightText: 2021-2024 Ole Tange, http://ole.tange.dk and Free Software and Foundation, Inc.
+# SPDX-License-Identifier: GPL-3.0-or-later
+# shellcheck disable=SC2006
+
+env_parallel() {
+ # env_parallel.{sh,ash,dash,bash,ksh,mksh,zsh}
+
+ # Check shell dialect
+ if [ -n "$BASH_VERSION" ]; then
+ _shell_DIALECT=bash
+ _eval_needed=false
+ _prefix_PARALLEL_ENV=_prefix_PARALLEL_ENV_bash
+ elif [ -n "$ZSH_VERSION" ]; then
+ _shell_DIALECT=zsh
+ _eval_needed=true
+ _prefix_PARALLEL_ENV=false
+ elif [ -n "$KSH_VERSION" ]; then
+ _shell_DIALECT=ksh
+ _eval_needed=false
+ _prefix_PARALLEL_ENV=false
+ else
+ # Dash/ash - can these be detected better?
+ _shell_DIALECT=sh
+ _eval_needed=false
+ _prefix_PARALLEL_ENV=false
+ fi
+ _names_of_ALIASES() {
+ _names_of_ALIASES_$_shell_DIALECT
+ }
+ _names_of_ALIASES_sh() {
+ # alias fails on Unixware 5
+ for _i in `alias 2>/dev/null | perl -ne 's/^alias //;s/^(\S+)=.*/$1/ && print' 2>/dev/null`; do
+ # Check if this name really is an alias
+ # or just part of a multiline alias definition
+ if alias "$_i" >/dev/null 2>/dev/null; then
+ echo "$_i"
+ fi
+ done
+ }
+ _names_of_ALIASES_bash() {
+ # No aliases will return false. This error should be ignored.
+ compgen -a || true
+ }
+ _names_of_ALIASES_ksh() {
+ alias | perl -pe 's/=.*//'
+ }
+ _names_of_ALIASES_zsh() {
+ print -l ${(k)aliases}
+ }
+ _bodies_of_ALIASES() {
+ _bodies_of_ALIASES_$_shell_DIALECT "$@"
+ }
+ _bodies_of_ALIASES_sh() {
+ # alias may return:
+ # myalias='definition' (GNU/Linux ash)
+ # alias myalias='definition' (FreeBSD ash)
+ # so remove 'alias ' from first line
+ for _i in "$@"; do
+ echo 'alias '"`alias "$_i" | perl -pe '1..1 and s/^alias //'`"
+ done
+ }
+ _bodies_of_ALIASES_bash() {
+ local _i
+ for _i in "$@"; do
+ # shellcheck disable=SC2046
+ if [ $(alias "$_i" | wc -l) == 1 ] ; then
+ true Alias is a single line. Good.
+ else
+ _warning_PAR "Alias '$_i' contains newline."
+ _warning_PAR "Make sure the command has at least one newline after '$_i'."
+ _warning_PAR "See BUGS in 'man env_parallel'."
+ fi
+ done
+ alias "$@"
+ }
+ _bodies_of_ALIASES_ksh() {
+ alias "$@" | perl -pe 's/^/alias /;
+ sub warning { print STDERR "env_parallel: Warning: @_\n"; }
+ if(/^alias (\S+)=\$.*\\n/) {
+ warning("Alias \"$1\" contains newline.");
+ warning("Make sure the command has at least one newline after \"$1\".");
+ warning("See BUGS in \"man env_parallel\".");
+ }'
+
+ }
+ _bodies_of_ALIASES_zsh() {
+ local _i
+ for _i in "$@"; do
+ echo 'alias '"$(alias $_i)"
+ done
+ }
+ _names_of_FUNCTIONS() {
+ _names_of_FUNCTIONS_$_shell_DIALECT
+ }
+ _names_of_FUNCTIONS_bash() {
+ compgen -A function
+ }
+ _names_of_maybe_FUNCTIONS() {
+ set | perl -ne '/^([A-Z_0-9]+)\s*\(\)\s*\{?$/i and print "$1\n"'
+ }
+ _names_of_FUNCTIONS_sh() {
+ # myfunc is a function
+ # shellcheck disable=SC2046
+ LANG=C type `_names_of_maybe_FUNCTIONS` |
+ perl -ne '/^(\S+) is a function$/ and not $seen{$1}++ and print "$1\n"'
+ }
+ _names_of_FUNCTIONS_ksh() {
+ # mksh = typeset +f
+ # ksh = typeset +p -f | perl -pe 's/\(\).*//'
+ typeset +f | perl -pe 's/\(\).*//; s/ .*//;'
+ }
+ _names_of_FUNCTIONS_zsh() {
+ print -l ${(k)functions}
+ }
+ _bodies_of_FUNCTIONS() {
+ _bodies_of_FUNCTIONS_$_shell_DIALECT "$@"
+ }
+ _bodies_of_FUNCTIONS_sh() {
+ LANG=C type "$@" | perl -ne '/^(\S+) is a function$/ or print'
+ }
+ _bodies_of_FUNCTIONS_bash() {
+ typeset -f "$@"
+ }
+ _bodies_of_FUNCTIONS_ksh() {
+ functions "$@"
+ }
+ _bodies_of_FUNCTIONS_zsh() {
+ typeset -f "$@"
+ }
+ _names_of_VARIABLES() {
+ _names_of_VARIABLES_$_shell_DIALECT
+ }
+ _names_of_VARIABLES_sh() {
+ # This may screw up if variables contain \n and =
+ set | perl -ne 's/^(\S+?)=.*/$1/ and print;'
+ }
+ _names_of_VARIABLES_bash() {
+ compgen -A variable
+ }
+ _names_of_VARIABLES_ksh() {
+ # mksh: typeset +p |
+ # perl -pe 's/^(type)?set( [-+][a-zA-Z0-9]*)* //; s/(\[\d+\])?=.*//' |
+ # uniq
+ # ksh: typeset +p | perl -pe 's/^typeset .. //'
+ typeset +p |
+ perl -pe 's/^(type)?set( [-+][a-zA-Z0-9]*)* //; s/(\[\d+\])?=.*//' |
+ uniq
+ }
+ _names_of_VARIABLES_zsh() {
+ print -l ${(k)parameters}
+ }
+ _bodies_of_VARIABLES() {
+ _bodies_of_VARIABLES_$_shell_DIALECT "$@"
+ }
+ _bodies_of_VARIABLES_sh() {
+ # Crappy typeset -p
+ for _i in "$@"
+ do
+ perl -e 'print @ARGV' "$_i="
+ eval echo "\"\$$_i\"" | perl -e '$/=undef; $a=<>; chop($a); print $a' |
+ perl -pe 's/[\002-\011\013-\032\\\#\?\`\(\)\{\}\[\]\^\*\<\=\>\~\|\; \"\!\$\&\202-\377]/\\$&/go;'"s/'/\\\'/g; s/[\n]/'\\n'/go;";
+ echo
+ done
+ }
+ _bodies_of_VARIABLES_bash() {
+ typeset -p "$@"
+ }
+ _bodies_of_VARIABLES_ksh() {
+ typeset -p "$@"
+ }
+ _bodies_of_VARIABLES_zsh() {
+ typeset -p "$@"
+ }
+ _ignore_HARDCODED() {
+ _ignore_HARDCODED_$_shell_DIALECT
+ }
+ _ignore_HARDCODED_sh() {
+ # These names cannot be detected
+ echo '(_|TIMEOUT|IFS)'
+ }
+ _ignore_HARDCODED_bash() {
+ # Copying $RANDOM will cause it not to be random
+ # The rest cannot be detected as read-only
+ echo '(RANDOM|_|TIMEOUT|GROUPS|FUNCNAME|DIRSTACK|PIPESTATUS|USERNAME|BASHPID|BASH_[A-Z_]+)'
+ }
+ _ignore_HARDCODED_ksh() {
+ # These names cannot be detected
+ echo '(_|TIMEOUT|IFS)'
+ }
+ _ignore_HARDCODED_zsh() {
+ # These names cannot be detected
+ echo '([-\?\#\!\$\*\@\_0]|zsh_eval_context|ZSH_EVAL_CONTEXT|LINENO|IFS|commands|functions|options|aliases|EUID|EGID|UID|GID|dis_patchars|patchars|terminfo|galiases|keymaps|parameters|jobdirs|dirstack|functrace|funcsourcetrace|zsh_scheduled_events|dis_aliases|dis_reswords|dis_saliases|modules|reswords|saliases|widgets|userdirs|historywords|nameddirs|termcap|dis_builtins|dis_functions|jobtexts|funcfiletrace|dis_galiases|builtins|history|jobstates|funcstack|run-help)'
+ }
+ _ignore_READONLY() {
+ _ignore_READONLY_$_shell_DIALECT
+ }
+ _parse_READONLY() {
+ # shellcheck disable=SC1078,SC1079,SC2026
+ perl -e '@r = map {
+ chomp;
+ # sh on UnixWare: readonly TIMEOUT
+ # ash: readonly var='val'
+ # ksh: var='val'
+ # mksh: PIPESTATUS[0]
+ s/^(readonly )?([^=\[ ]*?)(\[\d+\])?(=.*|)$/$2/ or
+ # bash: declare -ar BASH_VERSINFO=([0]="4" [1]="4")
+ # zsh: typeset -r var='val'
+ s/^\S+\s+\S+\s+(\S[^=]*)(=.*|$)/$1/;
+ $_ } <>;
+ $vars = join "|",map { quotemeta $_ } @r;
+ print $vars ? "($vars)" : "(,,nO,,VaRs,,)";
+ '
+ }
+ _ignore_READONLY_sh() {
+ readonly | _parse_READONLY
+ }
+ _ignore_READONLY_bash() {
+ readonly | _parse_READONLY
+ }
+ _ignore_READONLY_ksh() {
+ readonly | _parse_READONLY
+ }
+ _ignore_READONLY_zsh() {
+ typeset -pr | _parse_READONLY
+ }
+ _remove_bad_NAMES() {
+ # Do not transfer vars and funcs from env_parallel
+ # shellcheck disable=SC2006
+ _ignore_RO="`_ignore_READONLY`"
+ # shellcheck disable=SC2006
+ _ignore_HARD="`_ignore_HARDCODED`"
+ # To avoid depending on grep dialect, use Perl version of:
+ # grep -Ev '^(...)$' |
+ perl -ne '/^(
+ PARALLEL_ENV|
+ PARALLEL_TMP|
+ _alias_NAMES|
+ _bodies_of_ALIASES|
+ _bodies_of_FUNCTIONS|
+ _bodies_of_VARIABLES|
+ _error_PAR|
+ _function_NAMES|
+ _get_ignored_VARS|
+ _grep_REGEXP|
+ _ignore_HARD|
+ _ignore_HARDCODED|
+ _ignore_READONLY|
+ _ignore_RO|
+ _ignore_UNDERSCORE|
+ _list_alias_BODIES|
+ _list_function_BODIES|
+ _list_variable_VALUES|
+ _make_grep_REGEXP|
+ _names_of_ALIASES|
+ _names_of_FUNCTIONS|
+ _names_of_VARIABLES|
+ _names_of_maybe_FUNCTIONS|
+ _parallel_exit_CODE|
+ _prefix_PARALLEL_ENV|
+ _prefix_PARALLEL_ENV|
+ _remove_bad_NAMES|
+ _remove_readonly|
+ _variable_NAMES|
+ _warning_PAR|
+ _which_PAR)$/x and next;
+ # Filter names matching --env
+ /^'"$_grep_REGEXP"'$/ or next;
+ /^'"$_ignore_UNDERSCORE"'$/ and next;
+ # Remove readonly variables
+ /^'"$_ignore_RO"'$/ and next;
+ /^'"$_ignore_HARD"'$/ and next;
+ print;'
+ }
+ _prefix_PARALLEL_ENV_bash() {
+ shopt 2>/dev/null |
+ perl -pe 's:\s+off:;: and s/^/shopt -u /;
+ s:\s+on:;: and s/^/shopt -s /;
+ s:;$:&>/dev/null;:';
+ echo 'shopt -s expand_aliases &>/dev/null';
+ }
+
+ _get_ignored_VARS() {
+ perl -e '
+ for(@ARGV){
+ $next_is_env and push @envvar, split/,/, $_;
+ $next_is_env=/^--env$/;
+ }
+ if(grep { /^_$/ } @envvar) {
+ if(not open(IN, "<", "$ENV{HOME}/.parallel/ignored_vars")) {
+ print STDERR "parallel: Error: ",
+ "Run \"parallel --record-env\" in a clean environment first.\n";
+ } else {
+ chomp(@ignored_vars = <IN>);
+ }
+ }
+ if($ENV{PARALLEL_IGNORED_NAMES}) {
+ push @ignored_vars, split/\s+/, $ENV{PARALLEL_IGNORED_NAMES};
+ chomp @ignored_vars;
+ }
+ $vars = join "|",map { quotemeta $_ } @ignored_vars;
+ print $vars ? "($vars)" : "(,,nO,,VaRs,,)";
+ ' -- "$@"
+ }
+
+ # Get the --env variables if set
+ # --env _ should be ignored
+ # and convert a b c to (a|b|c)
+ # If --env not set: Match everything (.*)
+ _make_grep_REGEXP() {
+ perl -e '
+ for(@ARGV){
+ /^_$/ and $next_is_env = 0;
+ $next_is_env and push @envvar, split/,/, $_;
+ $next_is_env = /^--env$/;
+ }
+ $vars = join "|",map { quotemeta $_ } @envvar;
+ print $vars ? "($vars)" : "(.*)";
+ ' -- "$@"
+ }
+ _which_PAR() {
+ # type returns:
+ # ll is an alias for ls -l (in ash)
+ # bash is a tracked alias for /bin/bash
+ # true is a shell builtin (in bash)
+ # myfunc is a function (in bash)
+ # myfunc is a shell function (in zsh)
+ # which is /usr/bin/which (in sh, bash)
+ # which is hashed (/usr/bin/which)
+ # gi is aliased to `grep -i' (in bash)
+ # aliased to `alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
+ # Return 0 if found, 1 otherwise
+ LANG=C type "$@" |
+ perl -pe '$exit += (s/ is an alias for .*// ||
+ s/ is aliased to .*// ||
+ s/ is a function// ||
+ s/ is a shell function// ||
+ s/ is a shell builtin// ||
+ s/.* is hashed .(\S+).$/$1/ ||
+ s/.* is (a tracked alias for )?//);
+ END { exit not $exit }'
+ }
+ _warning_PAR() {
+ echo "env_parallel: Warning: $*" >&2
+ }
+ _error_PAR() {
+ echo "env_parallel: Error: $*" >&2
+ }
+
+ if _which_PAR parallel >/dev/null; then
+ true parallel found in path
+ else
+ # shellcheck disable=SC2016
+ _error_PAR 'parallel must be in $PATH.'
+ return 255
+ fi
+
+ # Grep regexp for vars given by --env
+ # shellcheck disable=SC2006
+ _grep_REGEXP="`_make_grep_REGEXP \"$@\"`"
+ unset _make_grep_REGEXP
+
+ # Deal with --env _
+ # shellcheck disable=SC2006
+ _ignore_UNDERSCORE="`_get_ignored_VARS \"$@\"`"
+ unset _get_ignored_VARS
+
+ # --record-env
+ if perl -e 'exit grep { /^--record-env$/ } @ARGV' -- "$@"; then
+ true skip
+ else
+ (_names_of_ALIASES;
+ _names_of_FUNCTIONS;
+ _names_of_VARIABLES) |
+ cat > "$HOME"/.parallel/ignored_vars
+ return 0
+ fi
+
+ # --session
+ if perl -e 'exit grep { /^--session$/ } @ARGV' -- "$@"; then
+ true skip
+ else
+ # Insert ::: between each level of session
+ # so you can pop off the last ::: at --end-session
+ # shellcheck disable=SC2006
+ PARALLEL_IGNORED_NAMES="`echo \"$PARALLEL_IGNORED_NAMES\";
+ echo :::;
+ (_names_of_ALIASES;
+ _names_of_FUNCTIONS;
+ _names_of_VARIABLES) | perl -ne '
+ BEGIN{
+ map { $ignored_vars{$_}++ }
+ split/\s+/, $ENV{PARALLEL_IGNORED_NAMES};
+ }
+ chomp;
+ for(split/\s+/) {
+ if(not $ignored_vars{$_}) {
+ print $_,\"\\n\";
+ }
+ }
+ '`"
+ export PARALLEL_IGNORED_NAMES
+ return 0
+ fi
+ if perl -e 'exit grep { /^--end.?session$/ } @ARGV' -- "$@"; then
+ true skip
+ else
+ # Pop off last ::: from PARALLEL_IGNORED_NAMES
+ # shellcheck disable=SC2006
+ PARALLEL_IGNORED_NAMES="`perl -e '
+ $ENV{PARALLEL_IGNORED_NAMES} =~ s/(.*):::.*?$/$1/s;
+ print $ENV{PARALLEL_IGNORED_NAMES}
+ '`"
+ return 0
+ fi
+ # Grep alias names
+ # shellcheck disable=SC2006
+ _alias_NAMES="`_names_of_ALIASES | _remove_bad_NAMES | xargs echo`"
+ _list_alias_BODIES="_bodies_of_ALIASES $_alias_NAMES"
+ if [ "$_alias_NAMES" = "" ] ; then
+ # no aliases selected
+ _list_alias_BODIES="true"
+ fi
+ unset _alias_NAMES
+
+ # Grep function names
+ # shellcheck disable=SC2006
+ _function_NAMES="`_names_of_FUNCTIONS | _remove_bad_NAMES | xargs echo`"
+ _list_function_BODIES="_bodies_of_FUNCTIONS $_function_NAMES"
+ if [ "$_function_NAMES" = "" ] ; then
+ # no functions selected
+ _list_function_BODIES="true"
+ fi
+ unset _function_NAMES
+
+ # Grep variable names
+ # shellcheck disable=SC2006
+ _variable_NAMES="`_names_of_VARIABLES | _remove_bad_NAMES | xargs echo`"
+ _list_variable_VALUES="_bodies_of_VARIABLES $_variable_NAMES"
+ if [ "$_variable_NAMES" = "" ] ; then
+ # no variables selected
+ _list_variable_VALUES="true"
+ fi
+ unset _variable_NAMES
+
+ if $eval_needed ; then
+ # shellcheck disable=SC2006
+ PARALLEL_ENV="`
+ eval $_list_alias_BODIES;
+ eval $_list_function_BODIES;
+ eval $_list_variable_VALUES;
+ `"
+ else
+ # shellcheck disable=SC2006
+ PARALLEL_ENV="`
+ $_prefix_PARALLEL_ENV;
+ $_list_alias_BODIES;
+ $_list_function_BODIES;
+ $_list_variable_VALUES;
+ `"
+ fi
+ export PARALLEL_ENV
+ # Free up some env space
+ unset _list_alias_BODIES _list_variable_VALUES _list_function_BODIES
+ unset _bodies_of_ALIASES _bodies_of_VARIABLES _bodies_of_FUNCTIONS
+ unset _names_of_ALIASES _names_of_VARIABLES _names_of_FUNCTIONS
+ unset _ignore_HARDCODED _ignore_READONLY _ignore_UNDERSCORE
+ unset _remove_bad_NAMES _grep_REGEXP
+ unset _prefix_PARALLEL_ENV
+ # Test if environment is too big by running 'true'
+ # shellcheck disable=SC2006,SC2092
+ if `_which_PAR true` >/dev/null 2>/dev/null ; then
+ parallel "$@"
+ _parallel_exit_CODE=$?
+ # Clean up variables/functions
+ unset PARALLEL_ENV
+ unset _which_PAR _which_TRUE
+ unset _warning_PAR _error_PAR
+ # Unset _parallel_exit_CODE before return
+ eval "unset _parallel_exit_CODE; return $_parallel_exit_CODE"
+ else
+ unset PARALLEL_ENV;
+ _error_PAR "Your environment is too big."
+ _error_PAR "You can try 3 different approaches:"
+ _error_PAR "1. Run 'env_parallel --session' before you set"
+ _error_PAR " variables or define functions."
+ _error_PAR "2. Use --env and only mention the names to copy."
+ _error_PAR "3. Try running this in a clean environment once:"
+ _error_PAR " env_parallel --record-env"
+ _error_PAR " And then use '--env _'"
+ _error_PAR "For details see: man env_parallel"
+ return 255
+ fi
+}
+
+parset() {
+ _parset_PARALLEL_PRG=parallel
+ _parset_main "$@"
+}
+
+env_parset() {
+ _parset_PARALLEL_PRG=env_parallel
+ _parset_main "$@"
+}
+
+_parset_main() {
+ # If $1 contains ',' or space:
+ # Split on , to get the destination variable names
+ # If $1 is a single destination variable name:
+ # Treat it as the name of an array
+ #
+ # # Create array named myvar
+ # parset myvar echo ::: {1..10}
+ # echo ${myvar[5]}
+ #
+ # # Put output into $var_a $var_b $var_c
+ # varnames=(var_a var_b var_c)
+ # parset "${varnames[*]}" echo ::: {1..3}
+ # echo $var_c
+ #
+ # # Put output into $var_a4 $var_b4 $var_c4
+ # parset "var_a4 var_b4 var_c4" echo ::: {1..3}
+ # echo $var_c4
+
+ _parset_NAME="$1"
+ if [ "$_parset_NAME" = "" ] ; then
+ echo parset: Error: No destination variable given. >&2
+ echo parset: Error: Try: >&2
+ echo parset: Error: ' ' parset myarray echo ::: foo bar >&2
+ return 255
+ fi
+ if [ "$_parset_NAME" = "--help" ] ; then
+ echo parset: Error: Usage: >&2
+ echo parset: Error: ' ' parset varname GNU Parallel options and command >&2
+ echo
+ parallel --help
+ return 255
+ fi
+ if [ "$_parset_NAME" = "--version" ] ; then
+ # shellcheck disable=SC2006
+ echo "parset 20240222 (GNU parallel `parallel --minversion 1`)"
+ echo "Copyright (C) 2007-2024 Ole Tange, http://ole.tange.dk and Free Software"
+ echo "Foundation, Inc."
+ echo "License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>"
+ echo "This is free software: you are free to change and redistribute it."
+ echo "GNU parallel comes with no warranty."
+ echo
+ echo "Web site: https://www.gnu.org/software/parallel"
+ echo
+ echo "When using programs that use GNU Parallel to process data for publication"
+ echo "please cite as described in 'parallel --citation'."
+ echo
+ return 255
+ fi
+ shift
+
+ # Bash: declare -A myassoc=( )
+ # Zsh: typeset -A myassoc=( )
+ # Ksh: typeset -A myassoc=( )
+ # shellcheck disable=SC2039,SC2169
+ if (typeset -p "$_parset_NAME" 2>/dev/null; echo) |
+ perl -ne 'exit not (/^declare[^=]+-A|^typeset[^=]+-A/)' ; then
+ # This is an associative array
+ # shellcheck disable=SC2006
+ eval "`$_parset_PARALLEL_PRG -k --_parset assoc,"$_parset_NAME" "$@"`"
+ # The eval returns the function!
+ else
+ # This is a normal array or a list of variable names
+ # shellcheck disable=SC2006
+ eval "`$_parset_PARALLEL_PRG -k --_parset var,"$_parset_NAME" "$@"`"
+ # The eval returns the function!
+ fi
+}
diff --git a/src/env_parallel.pdksh b/src/env_parallel.pdksh
new file mode 100755
index 0000000..1a25dcd
--- /dev/null
+++ b/src/env_parallel.pdksh
@@ -0,0 +1,183 @@
+#!/usr/bin/env pdksh
+
+# This file must be sourced in pdksh:
+#
+# source env_parallel.pdksh
+#
+# after which 'env_parallel' works
+#
+#
+# Copyright (C) 2016-2024 Ole Tange, http://ole.tange.dk and 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/>
+# or write to the Free Software Foundation, Inc., 51 Franklin St,
+# Fifth Floor, Boston, MA 02110-1301 USA
+#
+# SPDX-FileCopyrightText: 2021-2024 Ole Tange, http://ole.tange.dk and Free Software and Foundation, Inc.
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+env_parallel() {
+ # env_parallel.pdksh
+
+ _names_of_ALIASES() {
+ compgen -a
+ }
+ _bodies_of_ALIASES() {
+ alias "$@" | perl -pe 's/^/alias /'
+ }
+ _names_of_FUNCTIONS() {
+ compgen -A function
+ }
+ _bodies_of_FUNCTIONS() {
+ typeset -f "$@"
+ }
+ _names_of_VARIABLES() {
+ compgen -A variable
+ }
+ _bodies_of_VARIABLES() {
+ typeset -p "$@"
+ }
+ _remove_bad_NAMES() {
+ _tmp_READONLY="$(mktemp)"
+ readonly > "$_tmp_READONLY"
+ # Do not transfer vars and funcs from env_parallel
+ 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)$' |
+ # Filter names matching --env
+ grep -E "^$_grep_REGEXP"\$ | grep -vE "^$_ignore_UNDERSCORE"\$ |
+ grep -vFf $_tmp_READONLY |
+ grep -Ev '^(PIPESTATUS)'
+ rm $_tmp_READONLY
+ unset _tmp_READONLY
+ }
+ _prefix_PARALLEL_ENV() {
+ shopt 2>/dev/null |
+ perl -pe 's:\s+off:;: and s/^/shopt -u /;
+ s:\s+on:;: and s/^/shopt -s /;
+ s:;$:&>/dev/null;:';
+ echo 'shopt -s expand_aliases &>/dev/null';
+ }
+
+ _get_ignored_VARS() {
+ perl -e '
+ for(@ARGV){
+ $next_is_env and push @envvar, split/,/, $_;
+ $next_is_env=/^--env$/;
+ }
+ if(grep { /^_$/ } @envvar) {
+ if(not open(IN, "<", "$ENV{HOME}/.parallel/ignored_vars")) {
+ print STDERR "parallel: Error: ",
+ "Run \"parallel --record-env\" in a clean environment first.\n";
+ } else {
+ chomp(@ignored_vars = <IN>);
+ $vars = join "|",map { quotemeta $_ } @ignored_vars;
+ print $vars ? "($vars)" : "(,,nO,,VaRs,,)";
+ }
+ }
+ ' -- "$@"
+ }
+
+ # Get the --env variables if set
+ # --env _ should be ignored
+ # and convert a b c to (a|b|c)
+ # If --env not set: Match everything (.*)
+ _make_grep_REGEXP() {
+ perl -e '
+ for(@ARGV){
+ /^_$/ and $next_is_env = 0;
+ $next_is_env and push @envvar, split/,/, $_;
+ $next_is_env = /^--env$/;
+ }
+ $vars = join "|",map { quotemeta $_ } @envvar;
+ print $vars ? "($vars)" : "(.*)";
+ ' -- "$@"
+ }
+
+ if which parallel | grep 'no parallel in' >/dev/null; then
+ echo 'env_parallel: Error: parallel must be in $PATH.' >&2
+ return 1
+ fi
+ if which parallel >/dev/null; then
+ true which on linux
+ else
+ echo 'env_parallel: Error: parallel must be in $PATH.' >&2
+ return 1
+ fi
+
+ # Grep regexp for vars given by --env
+ _grep_REGEXP="`_make_grep_REGEXP \"$@\"`"
+ unset _make_grep_REGEXP
+
+ # Deal with --env _
+ _ignore_UNDERSCORE="`_get_ignored_VARS \"$@\"`"
+ unset _get_ignored_VARS
+
+ # --record-env
+ if perl -e 'exit grep { /^--record-env$/ } @ARGV' -- "$@"; then
+ true skip
+ else
+ (_names_of_ALIASES;
+ _names_of_FUNCTIONS;
+ _names_of_VARIABLES) |
+ cat > $HOME/.parallel/ignored_vars
+ return 0
+ fi
+
+ # Grep alias names
+ _alias_NAMES="`_names_of_ALIASES | _remove_bad_NAMES | xargs echo`"
+ _list_alias_BODIES="_bodies_of_ALIASES $_alias_NAMES"
+ if [ "$_alias_NAMES" = "" ] ; then
+ # no aliases selected
+ _list_alias_BODIES="true"
+ fi
+ unset _alias_NAMES
+
+ # Grep function names
+ _function_NAMES="`_names_of_FUNCTIONS | _remove_bad_NAMES | xargs echo`"
+ _list_function_BODIES="_bodies_of_FUNCTIONS $_function_NAMES"
+ if [ "$_function_NAMES" = "" ] ; then
+ # no functions selected
+ _list_function_BODIES="true"
+ fi
+ unset _function_NAMES
+
+ # Grep variable names
+ _variable_NAMES="`_names_of_VARIABLES | _remove_bad_NAMES | xargs echo`"
+ _list_variable_VALUES="_bodies_of_VARIABLES $_variable_NAMES"
+ if [ "$_variable_NAMES" = "" ] ; then
+ # no variables selected
+ _list_variable_VALUES="true"
+ fi
+ unset _variable_NAMES
+
+ # eval is needed for aliases - cannot explain why
+ export PARALLEL_ENV="`
+ eval $_list_alias_BODIES;
+ $_list_function_BODIES
+ $_list_variable_VALUES;
+ `";
+ unset _list_alias_BODIES _list_variable_VALUES _list_function_BODIES
+ unset _bodies_of_ALIASES _bodies_of_VARIABLES _bodies_of_FUNCTIONS
+ unset _names_of_ALIASES _names_of_VARIABLES _names_of_FUNCTIONS
+ unset _ignore_HARDCODED _ignore_READONLY _ignore_UNDERSCORE
+ unset _remove_bad_NAMES _grep_REGEXP
+ unset _prefix_PARALLEL_ENV
+ `which parallel` "$@"
+ _parallel_exit_CODE=$?
+ unset PARALLEL_ENV;
+ unset _which_PAR _which_TRUE
+ unset _warning_PAR _error_PAR
+ # Unset _parallel_exit_CODE before return
+ eval "unset _parallel_exit_CODE; return $_parallel_exit_CODE"
+}
diff --git a/src/env_parallel.pod b/src/env_parallel.pod
new file mode 100644
index 0000000..c59ba5d
--- /dev/null
+++ b/src/env_parallel.pod
@@ -0,0 +1,942 @@
+#!/usr/bin/perl -w
+
+# SPDX-FileCopyrightText: 2021-2024 Ole Tange, http://ole.tange.dk and Free Software and Foundation, Inc.
+# SPDX-License-Identifier: GFDL-1.3-or-later
+# SPDX-License-Identifier: CC-BY-SA-4.0
+
+=encoding utf8
+
+=head1 NAME
+
+env_parallel - export environment to GNU parallel
+
+
+=head1 SYNOPSIS
+
+B<env_parallel> [--record-env|--session|--end-session]
+ [options for GNU Parallel]
+
+
+=head1 DESCRIPTION
+
+B<env_parallel> is a shell function that exports the current
+environment to GNU B<parallel>.
+
+If the shell function is not loaded, a dummy script will be run
+instead that explains how to install the function.
+
+B<env_parallel> is 100 ms slower at startup than pure GNU B<parallel>,
+and takes up to 30% longer to start a job (typically 15 ms).
+
+Due to the problem with environment space (see below) you are
+recommended only to transfer the environment that you need.
+
+To help you do that, you can mark names that should not be
+transferred. This can be done with either B<--session> or
+B<--record-env>.
+
+ # Record the "clean" environment (this only needs to be run once)
+ env_parallel --record-env
+
+ # Optionally edit ~/.parallel/ignored_vars (only needed once)
+
+ # Define whatever you want to use
+ myfunc() { myalias and functions $myvar work. $1.; }
+ alias myalias='echo Aliases'
+ myvar='and variables'
+
+ # Use --env _ to only transfer the names not in the "empty" environment
+ env_parallel --env _ -S localhost myfunc ::: Hooray
+
+Or:
+
+ # Do --record-env into $PARALLEL_IGNORED_NAMES
+ env_parallel --session
+
+ # Define whatever you want to use
+ myfunc() { myalias and functions $myvar work. $1.; }
+ alias myalias='echo Aliases'
+ myvar='and variables'
+
+ # env_parallel will not export names in $PARALLEL_IGNORED_NAMES
+ env_parallel -S localhost myfunc ::: Hooray
+
+ # Optionally
+ env_parallel --end-session
+
+In B<csh> B<--session> is not supported:
+
+ # Record the "clean" environment - this only needs to be run once
+ env_parallel --record-env
+
+ # Optionally edit ~/.parallel/ignored_vars - only needed once
+
+ # Define whatever you want to use
+ alias myalias 'echo Aliases $myvar \!*.'
+ set myvar='and variables'
+
+ # Use --env _ to only transfer the names not in the "empty" environment
+ env_parallel --env _ -S localhost myalias ::: work
+
+=head2 Environment space
+
+By default B<env_parallel> will export all environment variables,
+arrays, aliases, functions and shell options (see details for the
+individual shells below).
+
+But this only works if the size of the current environment is smaller
+than the maximal length of a command and smaller than half of the max
+if running remotely. E.g. The max size of Bash's command is 128 KB, so
+B<env_parallel> will fail if 'B<set | wc -c>' is bigger than 128
+KB. Technically the limit is in execve(1) which IPC::open3 uses.
+
+Bash completion functions are well-known for taking up well over 128
+KB of environment space and the primary reason for causing
+B<env_parallel> to fail.
+
+Instead you can use B<--env> to specify which variables, arrays,
+aliases and functions to export as this will only export those with
+the given name. Or follow the recommended usage in shown in
+DESCRIPTION.
+
+
+=head1 OPTIONS
+
+Same as GNU B<parallel> in addition to these:
+
+=over 4
+
+=item B<--end-session>
+
+Undo last B<--session>
+
+
+=item B<--record-env>
+
+Record all names currently defined to be ignored every time running
+B<env_parallel> in the future.
+
+
+=item B<--session>
+
+Ignore all names currently defined. Aliases, variables, arrays, and
+functions currently defined will not be transferred.
+
+But names defined I<after> running B<parallel --session> I<will> be
+transferred.
+
+This is only valid in the running shell, and can be undone with
+B<parallel --end-session>.
+
+You can run multiple B<--session> inside each other:
+
+ env_parallel --session
+ var=not
+ # var is transferred
+ env_parallel -Slocalhost 'echo var is $var' ::: ignored
+ env_parallel --session
+ # var is not transferred
+ env_parallel -Slocalhost 'echo var is $var' ::: ignored
+ env_parallel --end-session
+ # var is transferred again
+ env_parallel -Slocalhost 'echo var is $var' ::: ignored
+
+
+
+=back
+
+
+=head1 SUPPORTED SHELLS
+
+=head2 Ash
+
+=head3 Installation
+
+Put this in $HOME/.profile:
+
+ . env_parallel.ash
+
+E.g. by doing:
+
+ echo '. env_parallel.ash' >> $HOME/.profile
+
+=head3 Supported use
+
+B<--env> is supported to export only the variable, or alias with the
+given name. Multiple B<--env>s can be given.
+
+B<--session> is supported.
+
+=over 8
+
+=item aliases
+
+ alias myecho='echo aliases'
+ env_parallel myecho ::: work
+ env_parallel -S server myecho ::: work
+ env_parallel --env myecho myecho ::: work
+ env_parallel --env myecho -S server myecho ::: work
+
+ alias multiline='echo multiline
+ echo aliases'
+ env_parallel multiline ::: work
+ env_parallel -S server multiline ::: work
+ env_parallel --env multiline multiline ::: work
+ env_parallel --env multiline -S server multiline ::: work
+
+=item functions
+
+ ash cannot list defined functions - thus is not supported.
+
+=item variables
+
+ myvar=variables
+ env_parallel echo '$myvar' ::: work
+ env_parallel -S server echo '$myvar' ::: work
+ env_parallel --env myvar echo '$myvar' ::: work
+ env_parallel --env myvar -S server echo '$myvar' ::: work
+
+=item arrays
+
+Arrays are not supported by Ash.
+
+=back
+
+=head2 Bash
+
+=head3 Installation
+
+Put this in $HOME/.bashrc:
+
+ . env_parallel.bash
+
+E.g. by doing:
+
+ echo '. env_parallel.bash' >> $HOME/.bashrc
+
+=head3 Supported use
+
+B<--env> is supported to export only the variable, alias, function, or
+array with the given name. Multiple B<--env>s can be given.
+
+B<--session> is supported.
+
+=over 8
+
+=item aliases
+
+ alias myecho='echo aliases'
+ env_parallel myecho ::: work
+ env_parallel -S server myecho ::: work
+ env_parallel --env myecho myecho ::: work
+ env_parallel --env myecho -S server myecho ::: work
+
+ alias multiline='echo multiline
+ echo aliases'
+ env_parallel 'multiline {};
+ echo but only when followed by a newline' ::: work
+ env_parallel -S server 'multiline {};
+ echo but only when followed by a newline' ::: work
+ env_parallel --env multiline 'multiline {};
+ echo but only when followed by a newline' ::: work
+ env_parallel --env multiline -S server 'multiline {};
+ echo but only when followed by a newline' ::: work
+
+=item functions
+
+ myfunc() { echo functions $*; }
+ env_parallel myfunc ::: work
+ env_parallel -S server myfunc ::: work
+ env_parallel --env myfunc myfunc ::: work
+ env_parallel --env myfunc -S server myfunc ::: work
+
+=item variables
+
+ myvar=variables
+ env_parallel echo '$myvar' ::: work
+ env_parallel -S server echo '$myvar' ::: work
+ env_parallel --env myvar echo '$myvar' ::: work
+ env_parallel --env myvar -S server echo '$myvar' ::: work
+
+=item arrays
+
+ myarray=(arrays work, too)
+ env_parallel -k echo '${myarray[{}]}' ::: 0 1 2
+ env_parallel -k -S server echo '${myarray[{}]}' ::: 0 1 2
+ env_parallel -k --env myarray echo '${myarray[{}]}' ::: 0 1 2
+ env_parallel -k --env myarray -S server \
+ echo '${myarray[{}]}' ::: 0 1 2
+
+=back
+
+=head3 BUGS
+
+Due to a bug in Bash, aliases containing newlines must be followed by
+a newline in the command. Some systems are not affected by this bug,
+but will print a warning anyway.
+
+=head2 csh
+
+B<env_parallel> for B<csh> breaks B<$PARALLEL>, so do not use
+B<$PARALLEL>.
+
+=head3 Installation
+
+Put this in $HOME/.cshrc:
+
+ source `which env_parallel.csh`
+
+E.g. by doing:
+
+ echo 'source `which env_parallel.csh`' >> $HOME/.cshrc
+
+=head3 Supported use
+
+B<--env> is supported to export only the variable, alias, or
+array with the given name. Multiple B<--env>s can be given.
+
+=over 8
+
+=item aliases
+
+ alias myecho 'echo aliases'
+ env_parallel myecho ::: work
+ env_parallel -S server myecho ::: work
+ env_parallel --env myecho myecho ::: work
+ env_parallel --env myecho -S server myecho ::: work
+
+=item functions
+
+Not supported by B<csh>.
+
+=item variables
+
+ set myvar=variables
+ env_parallel echo '$myvar' ::: work
+ env_parallel -S server echo '$myvar' ::: work
+ env_parallel --env myvar echo '$myvar' ::: work
+ env_parallel --env myvar -S server echo '$myvar' ::: work
+
+=item arrays with no special chars
+
+ set myarray=(arrays work, too)
+ env_parallel -k echo \$'{myarray[{}]}' ::: 1 2 3
+ env_parallel -k -S server echo \$'{myarray[{}]}' ::: 1 2 3
+ env_parallel -k --env myarray echo \$'{myarray[{}]}' ::: 1 2 3
+ env_parallel -k --env myarray -S server \
+ echo \$'{myarray[{}]}' ::: 1 2 3
+
+=back
+
+
+=head2 Dash
+
+=head3 Installation
+
+Put this in $HOME/.profile:
+
+ . env_parallel.dash
+
+E.g. by doing:
+
+ echo '. env_parallel.dash' >> $HOME/.profile
+
+=head3 Supported use
+
+B<--env> is supported to export only the variable, or alias with the
+given name. Multiple B<--env>s can be given.
+
+B<--session> is supported.
+
+=over 8
+
+=item aliases
+
+ alias myecho='echo aliases'
+ env_parallel myecho ::: work
+ env_parallel -S server myecho ::: work
+ env_parallel --env myecho myecho ::: work
+ env_parallel --env myecho -S server myecho ::: work
+
+ alias multiline='echo multiline
+ echo aliases'
+ env_parallel multiline ::: work
+ env_parallel -S server multiline ::: work
+ env_parallel --env multiline multiline ::: work
+ env_parallel --env multiline -S server multiline ::: work
+
+=item functions
+
+ dash cannot list defined functions - thus is not supported.
+
+=item variables
+
+ myvar=variables
+ env_parallel echo '$myvar' ::: work
+ env_parallel -S server echo '$myvar' ::: work
+ env_parallel --env myvar echo '$myvar' ::: work
+ env_parallel --env myvar -S server echo '$myvar' ::: work
+
+=item arrays
+
+ dash does not support arrays.
+
+=back
+
+
+=head2 fish
+
+=head3 Installation
+
+Put this in $HOME/.config/fish/config.fish:
+
+ source (which env_parallel.fish)
+
+E.g. by doing:
+
+ echo 'source (which env_parallel.fish)' \
+ >> $HOME/.config/fish/config.fish
+
+=head3 Supported use
+
+B<--env> is supported to export only the variable, alias, function, or
+array with the given name. Multiple B<--env>s can be given.
+
+B<--session> is supported.
+
+=over 8
+
+=item aliases
+
+ alias myecho 'echo aliases'
+ env_parallel myecho ::: work
+ env_parallel -S server myecho ::: work
+ env_parallel --env myecho myecho ::: work
+ env_parallel --env myecho -S server myecho ::: work
+
+=item functions
+
+ function myfunc
+ echo functions $argv
+ end
+ env_parallel myfunc ::: work
+ env_parallel -S server myfunc ::: work
+ env_parallel --env myfunc myfunc ::: work
+ env_parallel --env myfunc -S server myfunc ::: work
+
+=item variables
+
+ set myvar variables
+ env_parallel echo '$myvar' ::: work
+ env_parallel -S server echo '$myvar' ::: work
+ env_parallel --env myvar echo '$myvar' ::: work
+ env_parallel --env myvar -S server echo '$myvar' ::: work
+
+=item arrays
+
+ set myarray arrays work, too
+ env_parallel -k echo '$myarray[{}]' ::: 1 2 3
+ env_parallel -k -S server echo '$myarray[{}]' ::: 1 2 3
+ env_parallel -k --env myarray echo '$myarray[{}]' ::: 1 2 3
+ env_parallel -k --env myarray -S server \
+ echo '$myarray[{}]' ::: 1 2 3
+
+=back
+
+
+=head2 ksh
+
+=head3 Installation
+
+Put this in $HOME/.kshrc:
+
+ source env_parallel.ksh
+
+E.g. by doing:
+
+ echo 'source env_parallel.ksh' >> $HOME/.kshrc
+
+=head3 Supported use
+
+B<--env> is supported to export only the variable, alias, function, or
+array with the given name. Multiple B<--env>s can be given.
+
+B<--session> is supported.
+
+=over 8
+
+=item aliases
+
+ alias myecho='echo aliases'
+ env_parallel myecho ::: work
+ env_parallel -S server myecho ::: work
+ env_parallel --env myecho myecho ::: work
+ env_parallel --env myecho -S server myecho ::: work
+
+ alias multiline='echo multiline
+ echo aliases'
+ env_parallel multiline ::: work
+ env_parallel -S server multiline ::: work
+ env_parallel --env multiline multiline ::: work
+ env_parallel --env multiline -S server multiline ::: work
+
+=item functions
+
+ myfunc() { echo functions $*; }
+ env_parallel myfunc ::: work
+ env_parallel -S server myfunc ::: work
+ env_parallel --env myfunc myfunc ::: work
+ env_parallel --env myfunc -S server myfunc ::: work
+
+=item variables
+
+ myvar=variables
+ env_parallel echo '$myvar' ::: work
+ env_parallel -S server echo '$myvar' ::: work
+ env_parallel --env myvar echo '$myvar' ::: work
+ env_parallel --env myvar -S server echo '$myvar' ::: work
+
+=item arrays
+
+ myarray=(arrays work, too)
+ env_parallel -k echo '${myarray[{}]}' ::: 0 1 2
+ env_parallel -k -S server echo '${myarray[{}]}' ::: 0 1 2
+ env_parallel -k --env myarray echo '${myarray[{}]}' ::: 0 1 2
+ env_parallel -k --env myarray -S server \
+ echo '${myarray[{}]}' ::: 0 1 2
+
+=back
+
+
+=head2 mksh
+
+=head3 Installation
+
+Put this in $HOME/.mkshrc:
+
+ source env_parallel.mksh
+
+E.g. by doing:
+
+ echo 'source env_parallel.mksh' >> $HOME/.mkshrc
+
+=head3 Supported use
+
+B<--env> is supported to export only the variable, alias, function, or
+array with the given name. Multiple B<--env>s can be given.
+
+B<--session> is supported.
+
+=over 8
+
+=item aliases
+
+ alias myecho='echo aliases'
+ env_parallel myecho ::: work
+ env_parallel -S server myecho ::: work
+ env_parallel --env myecho myecho ::: work
+ env_parallel --env myecho -S server myecho ::: work
+
+ alias multiline='echo multiline
+ echo aliases'
+ env_parallel multiline ::: work
+ env_parallel -S server multiline ::: work
+ env_parallel --env multiline multiline ::: work
+ env_parallel --env multiline -S server multiline ::: work
+
+=item functions
+
+ myfunc() { echo functions $*; }
+ env_parallel myfunc ::: work
+ env_parallel -S server myfunc ::: work
+ env_parallel --env myfunc myfunc ::: work
+ env_parallel --env myfunc -S server myfunc ::: work
+
+=item variables
+
+ myvar=variables
+ env_parallel echo '$myvar' ::: work
+ env_parallel -S server echo '$myvar' ::: work
+ env_parallel --env myvar echo '$myvar' ::: work
+ env_parallel --env myvar -S server echo '$myvar' ::: work
+
+=item arrays
+
+ myarray=(arrays work, too)
+ env_parallel -k echo '${myarray[{}]}' ::: 0 1 2
+ env_parallel -k -S server echo '${myarray[{}]}' ::: 0 1 2
+ env_parallel -k --env myarray echo '${myarray[{}]}' ::: 0 1 2
+ env_parallel -k --env myarray -S server \
+ echo '${myarray[{}]}' ::: 0 1 2
+
+=back
+
+
+=head2 pdksh
+
+=head3 Installation
+
+Put this in $HOME/.profile:
+
+ source env_parallel.pdksh
+
+E.g. by doing:
+
+ echo 'source env_parallel.pdksh' >> $HOME/.profile
+
+=head3 Supported use
+
+B<--env> is supported to export only the variable, alias, function, or
+array with the given name. Multiple B<--env>s can be given.
+
+B<--session> is supported.
+
+=over 8
+
+=item aliases
+
+ alias myecho="echo aliases";
+ env_parallel myecho ::: work;
+ env_parallel -S server myecho ::: work;
+ env_parallel --env myecho myecho ::: work;
+ env_parallel --env myecho -S server myecho ::: work
+
+=item functions
+
+ myfunc() { echo functions $*; };
+ env_parallel myfunc ::: work;
+ env_parallel -S server myfunc ::: work;
+ env_parallel --env myfunc myfunc ::: work;
+ env_parallel --env myfunc -S server myfunc ::: work
+
+=item variables
+
+ myvar=variables;
+ env_parallel echo "\$myvar" ::: work;
+ env_parallel -S server echo "\$myvar" ::: work;
+ env_parallel --env myvar echo "\$myvar" ::: work;
+ env_parallel --env myvar -S server echo "\$myvar" ::: work
+
+=item arrays
+
+ myarray=(arrays work, too);
+ env_parallel -k echo "\${myarray[{}]}" ::: 0 1 2;
+ env_parallel -k -S server echo "\${myarray[{}]}" ::: 0 1 2;
+ env_parallel -k --env myarray echo "\${myarray[{}]}" ::: 0 1 2;
+ env_parallel -k --env myarray -S server \
+ echo "\${myarray[{}]}" ::: 0 1 2
+
+=back
+
+
+=head2 sh
+
+=head3 Installation
+
+Put this in $HOME/.profile:
+
+ . env_parallel.sh
+
+E.g. by doing:
+
+ echo '. env_parallel.sh' >> $HOME/.profile
+
+=head3 Supported use
+
+B<--env> is supported to export only the variable, or alias with the
+given name. Multiple B<--env>s can be given.
+
+B<--session> is supported.
+
+=over 8
+
+=item aliases
+
+ sh does not support aliases.
+
+=item functions
+
+ myfunc() { echo functions $*; }
+ env_parallel myfunc ::: work
+ env_parallel -S server myfunc ::: work
+ env_parallel --env myfunc myfunc ::: work
+ env_parallel --env myfunc -S server myfunc ::: work
+
+=item variables
+
+ myvar=variables
+ env_parallel echo '$myvar' ::: work
+ env_parallel -S server echo '$myvar' ::: work
+ env_parallel --env myvar echo '$myvar' ::: work
+ env_parallel --env myvar -S server echo '$myvar' ::: work
+
+=item arrays
+
+ sh does not support arrays.
+
+=back
+
+
+=head2 tcsh
+
+B<env_parallel> for B<tcsh> breaks B<$PARALLEL>, so do not use
+B<$PARALLEL>.
+
+=head3 Installation
+
+Put this in $HOME/.tcshrc:
+
+ source `which env_parallel.tcsh`
+
+E.g. by doing:
+
+ echo 'source `which env_parallel.tcsh`' >> $HOME/.tcshrc
+
+=head3 Supported use
+
+B<--env> is supported to export only the variable, alias, or
+array with the given name. Multiple B<--env>s can be given.
+
+=over 8
+
+=item aliases
+
+ alias myecho 'echo aliases'
+ env_parallel myecho ::: work
+ env_parallel -S server myecho ::: work
+ env_parallel --env myecho myecho ::: work
+ env_parallel --env myecho -S server myecho ::: work
+
+=item functions
+
+Not supported by B<tcsh>.
+
+=item variables
+
+ set myvar=variables
+ env_parallel echo '$myvar' ::: work
+ env_parallel -S server echo '$myvar' ::: work
+ env_parallel --env myvar echo '$myvar' ::: work
+ env_parallel --env myvar -S server echo '$myvar' ::: work
+
+=item arrays with no special chars
+
+ set myarray=(arrays work, too)
+ env_parallel -k echo \$'{myarray[{}]}' ::: 1 2 3
+ env_parallel -k -S server echo \$'{myarray[{}]}' ::: 1 2 3
+ env_parallel -k --env myarray echo \$'{myarray[{}]}' ::: 1 2 3
+ env_parallel -k --env myarray -S server \
+ echo \$'{myarray[{}]}' ::: 1 2 3
+
+=back
+
+
+=head2 Zsh
+
+=head3 Installation
+
+Put this in $HOME/.zshrc:
+
+ . env_parallel.zsh
+
+E.g. by doing:
+
+ echo '. env_parallel.zsh' >> $HOME/.zshenv
+
+=head3 Supported use
+
+B<--env> is supported to export only the variable, alias, function, or
+array with the given name. Multiple B<--env>s can be given.
+
+B<--session> is supported.
+
+=over 8
+
+=item aliases
+
+ alias myecho='echo aliases'
+ env_parallel myecho ::: work
+ env_parallel -S server myecho ::: work
+ env_parallel --env myecho myecho ::: work
+ env_parallel --env myecho -S server myecho ::: work
+
+ alias multiline='echo multiline
+ echo aliases'
+ env_parallel multiline ::: work
+ env_parallel -S server multiline ::: work
+ env_parallel --env multiline multiline ::: work
+ env_parallel --env multiline -S server multiline ::: work
+
+=item functions
+
+ myfunc() { echo functions $*; }
+ env_parallel myfunc ::: work
+ env_parallel -S server myfunc ::: work
+ env_parallel --env myfunc myfunc ::: work
+ env_parallel --env myfunc -S server myfunc ::: work
+
+=item variables
+
+ myvar=variables
+ env_parallel echo '$myvar' ::: work
+ env_parallel -S server echo '$myvar' ::: work
+ env_parallel --env myvar echo '$myvar' ::: work
+ env_parallel --env myvar -S server echo '$myvar' ::: work
+
+=item arrays
+
+ myarray=(arrays work, too)
+ env_parallel -k echo '${myarray[{}]}' ::: 1 2 3
+ env_parallel -k -S server echo '${myarray[{}]}' ::: 1 2 3
+ env_parallel -k --env myarray echo '${myarray[{}]}' ::: 1 2 3
+ env_parallel -k --env myarray -S server \
+ echo '${myarray[{}]}' ::: 1 2 3
+
+=back
+
+
+=head1 EXIT STATUS
+
+Same as GNU B<parallel>.
+
+
+=head1 AUTHOR
+
+When using GNU B<env_parallel> for a publication please cite:
+
+O. Tange (2018): GNU Parallel 2018, March 2018, ISBN 9781387509881,
+DOI: 10.5281/zenodo.1146014.
+
+This helps funding further development; and it won't cost you a cent.
+If you pay 10000 EUR you should feel free to use GNU Parallel without citing.
+
+Copyright (C) 2007-10-18 Ole Tange, http://ole.tange.dk
+
+Copyright (C) 2008-2010 Ole Tange, http://ole.tange.dk
+
+Copyright (C) 2010-2024 Ole Tange, http://ole.tange.dk and Free
+Software Foundation, Inc.
+
+
+=head1 LICENSE
+
+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 LICENSES/GFDL-1.3-or-later.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 2
+
+=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
+
+=back
+
+=over 9
+
+=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
+LICENCES/CC-BY-SA-4.0.txt
+
+
+=head1 DEPENDENCIES
+
+B<env_parallel> uses GNU B<parallel>.
+
+
+=head1 SEE ALSO
+
+B<parallel>(1), B<ash>(1), B<bash>(1), B<csh>(1), B<dash>(1),
+B<fish>(1), B<ksh>(1), B<pdksh>(1) B<tcsh>(1), B<zsh>(1).
+
+
+=cut
diff --git a/src/env_parallel.sh b/src/env_parallel.sh
new file mode 100755
index 0000000..62c4729
--- /dev/null
+++ b/src/env_parallel.sh
@@ -0,0 +1,636 @@
+#!/usr/bin/env sh
+
+# This file must be sourced in sh/ash/dash/bash/ksh/mksh/zsh:
+#
+# . env_parallel.sh
+# source env_parallel.ash
+# source env_parallel.dash
+# source env_parallel.bash
+# source env_parallel.ksh
+# source env_parallel.mksh
+# source env_parallel.zsh
+#
+# after which 'env_parallel' works
+#
+#
+# Copyright (C) 2016-2024 Ole Tange, http://ole.tange.dk and 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/>
+# or write to the Free Software Foundation, Inc., 51 Franklin St,
+# Fifth Floor, Boston, MA 02110-1301 USA
+#
+# SPDX-FileCopyrightText: 2021-2024 Ole Tange, http://ole.tange.dk and Free Software and Foundation, Inc.
+# SPDX-License-Identifier: GPL-3.0-or-later
+# shellcheck disable=SC2006
+
+env_parallel() {
+ # env_parallel.{sh,ash,dash,bash,ksh,mksh,zsh}
+
+ # Check shell dialect
+ if [ -n "$BASH_VERSION" ]; then
+ _shell_DIALECT=bash
+ _eval_needed=false
+ _prefix_PARALLEL_ENV=_prefix_PARALLEL_ENV_bash
+ elif [ -n "$ZSH_VERSION" ]; then
+ _shell_DIALECT=zsh
+ _eval_needed=true
+ _prefix_PARALLEL_ENV=false
+ elif [ -n "$KSH_VERSION" ]; then
+ _shell_DIALECT=ksh
+ _eval_needed=false
+ _prefix_PARALLEL_ENV=false
+ else
+ # Dash/ash - can these be detected better?
+ _shell_DIALECT="sh"
+ _eval_needed=false
+ _prefix_PARALLEL_ENV=false
+ fi
+ _names_of_ALIASES() {
+ _names_of_ALIASES_$_shell_DIALECT
+ }
+ _names_of_ALIASES_sh() {
+ # alias fails on Unixware 5
+ for _i in `alias 2>/dev/null | perl -ne 's/^alias //;s/^(\S+)=.*/$1/ && print' 2>/dev/null`; do
+ # Check if this name really is an alias
+ # or just part of a multiline alias definition
+ if alias "$_i" >/dev/null 2>/dev/null; then
+ echo "$_i"
+ fi
+ done
+ }
+ _names_of_ALIASES_bash() {
+ # No aliases will return false. This error should be ignored.
+ # shellcheck disable=SC3044
+ compgen -a || true
+ }
+ _names_of_ALIASES_ksh() {
+ alias | perl -pe 's/=.*//'
+ }
+ _names_of_ALIASES_zsh() {
+ # shellcheck disable=SC2086,SC2296
+ print -l ${(k)aliases}
+ }
+ _bodies_of_ALIASES() {
+ _bodies_of_ALIASES_$_shell_DIALECT "$@"
+ }
+ _bodies_of_ALIASES_sh() {
+ # alias may return:
+ # myalias='definition' (GNU/Linux ash)
+ # alias myalias='definition' (FreeBSD ash)
+ # so remove 'alias ' from first line
+ for _i in "$@"; do
+ echo 'alias '"`alias "$_i" | perl -pe '1..1 and s/^alias //'`"
+ done
+ }
+ _bodies_of_ALIASES_bash() {
+ # shellcheck disable=SC3043
+ local _i
+ for _i in "$@"; do
+ # shellcheck disable=SC2046
+ if [ $(alias "$_i" | wc -l) = 1 ] ; then
+ true Alias is a single line. Good.
+ else
+ _warning_PAR "Alias '$_i' contains newline."
+ _warning_PAR "Make sure the command has at least one newline after '$_i'."
+ _warning_PAR "See BUGS in 'man env_parallel'."
+ fi
+ done
+ alias "$@"
+ }
+ _bodies_of_ALIASES_ksh() {
+ alias "$@" | perl -pe 's/^/alias /;
+ sub warning { print STDERR "env_parallel: Warning: @_\n"; }
+ if(/^alias (\S+)=\$.*\\n/) {
+ warning("Alias \"$1\" contains newline.");
+ warning("Make sure the command has at least one newline after \"$1\".");
+ warning("See BUGS in \"man env_parallel\".");
+ }'
+
+ }
+ _bodies_of_ALIASES_zsh() {
+ # shellcheck disable=SC3043
+ local _i
+ for _i in "$@"; do
+ echo 'alias '"$(alias "$_i")"
+ done
+ }
+ _names_of_FUNCTIONS() {
+ _names_of_FUNCTIONS_$_shell_DIALECT
+ }
+ _names_of_FUNCTIONS_bash() {
+ # shellcheck disable=SC3044
+ compgen -A function
+ }
+ _names_of_maybe_FUNCTIONS() {
+ set | perl -ne '/^([A-Z_0-9]+)\s*\(\)\s*\{?$/i and print "$1\n"'
+ }
+ _names_of_FUNCTIONS_sh() {
+ # myfunc is a function
+ # shellcheck disable=SC2046
+ LANG=C type `_names_of_maybe_FUNCTIONS` |
+ perl -ne '/^(\S+) is a function$/ and not $seen{$1}++ and print "$1\n"'
+ }
+ _names_of_FUNCTIONS_ksh() {
+ # shellcheck disable=SC3044
+ typeset +f | perl -pe 's/\(\).*//; s/ .*//;'
+ }
+ _names_of_FUNCTIONS_zsh() {
+ # shellcheck disable=SC2086,SC2296
+ print -l ${(k)functions}
+ }
+ _bodies_of_FUNCTIONS() {
+ _bodies_of_FUNCTIONS_$_shell_DIALECT "$@"
+ }
+ _bodies_of_FUNCTIONS_sh() {
+ LANG=C type "$@" | perl -ne '/^(\S+) is a function$/ or print'
+ }
+ _bodies_of_FUNCTIONS_bash() {
+ # shellcheck disable=SC3044
+ typeset -f "$@"
+ }
+ _bodies_of_FUNCTIONS_ksh() {
+ functions "$@"
+ }
+ _bodies_of_FUNCTIONS_zsh() {
+ # shellcheck disable=SC3044
+ typeset -f "$@"
+ }
+ _names_of_VARIABLES() {
+ _names_of_VARIABLES_$_shell_DIALECT
+ }
+ _names_of_VARIABLES_sh() {
+ # This may screw up if variables contain \n and =
+ set | perl -ne 's/^(\S+?)=.*/$1/ and print;'
+ }
+ _names_of_VARIABLES_bash() {
+ # shellcheck disable=SC3044
+ compgen -A variable
+ }
+ _names_of_VARIABLES_ksh() {
+ # shellcheck disable=SC3044
+ typeset +p |
+ perl -pe 's/^(type)?set( [-+][a-zA-Z0-9]*)* //; s/(\[\d+\])?=.*//' |
+ uniq
+ }
+ _names_of_VARIABLES_zsh() {
+ # shellcheck disable=SC2086,SC2296
+ print -l ${(k)parameters}
+ }
+ _bodies_of_VARIABLES() {
+ _bodies_of_VARIABLES_$_shell_DIALECT "$@"
+ }
+ _bodies_of_VARIABLES_sh() {
+ # Crappy typeset -p
+ for _i in "$@"
+ do
+ perl -e 'print @ARGV' "$_i="
+ eval echo "\"\$$_i\"" | perl -e '$/=undef; $a=<>; chop($a); print $a' |
+ perl -pe 's/[\002-\011\013-\032\\\#\?\`\(\)\{\}\[\]\^\*\<\=\>\~\|\; \"\!\$\&\202-\377]/\\$&/go;'"s/'/\\\'/g; s/[\n]/'\\n'/go;";
+ echo
+ done
+ }
+ _bodies_of_VARIABLES_bash() {
+ # shellcheck disable=SC3044
+ typeset -p "$@"
+ }
+ _bodies_of_VARIABLES_ksh() {
+ # shellcheck disable=SC3044
+ typeset -p "$@"
+ }
+ _bodies_of_VARIABLES_zsh() {
+ # shellcheck disable=SC3044
+ typeset -p "$@"
+ }
+ _ignore_HARDCODED() {
+ _ignore_HARDCODED_$_shell_DIALECT
+ }
+ _ignore_HARDCODED_sh() {
+ # These names cannot be detected
+ echo '(_|TIMEOUT|IFS)'
+ }
+ _ignore_HARDCODED_bash() {
+ # Copying $RANDOM will cause it not to be random
+ # The rest cannot be detected as read-only
+ echo '(RANDOM|_|TIMEOUT|GROUPS|FUNCNAME|DIRSTACK|PIPESTATUS|USERNAME|BASHPID|BASH_[A-Z_]+)'
+ }
+ _ignore_HARDCODED_ksh() {
+ # These names cannot be detected
+ echo '(_|TIMEOUT|IFS)'
+ }
+ _ignore_HARDCODED_zsh() {
+ # These names cannot be detected
+ echo '([-\?\#\!\$\*\@\_0]|zsh_eval_context|ZSH_EVAL_CONTEXT|LINENO|IFS|commands|functions|options|aliases|EUID|EGID|UID|GID|dis_patchars|patchars|terminfo|galiases|keymaps|parameters|jobdirs|dirstack|functrace|funcsourcetrace|zsh_scheduled_events|dis_aliases|dis_reswords|dis_saliases|modules|reswords|saliases|widgets|userdirs|historywords|nameddirs|termcap|dis_builtins|dis_functions|jobtexts|funcfiletrace|dis_galiases|builtins|history|jobstates|funcstack|run-help)'
+ }
+ _ignore_READONLY() {
+ _ignore_READONLY_$_shell_DIALECT
+ }
+ _parse_READONLY() {
+ # shellcheck disable=SC1078,SC1079,SC2026
+ perl -e '@r = map {
+ chomp;
+ # sh on UnixWare: readonly TIMEOUT
+ # ash: readonly var='val'
+ # ksh: var='val'
+ # mksh: PIPESTATUS[0]
+ s/^(readonly )?([^=\[ ]*?)(\[\d+\])?(=.*|)$/$2/ or
+ # bash: declare -ar BASH_VERSINFO=([0]="4" [1]="4")
+ # zsh: typeset -r var='val'
+ s/^\S+\s+\S+\s+(\S[^=]*)(=.*|$)/$1/;
+ $_ } <>;
+ $vars = join "|",map { quotemeta $_ } @r;
+ print $vars ? "($vars)" : "(,,nO,,VaRs,,)";
+ '
+ }
+ _ignore_READONLY_sh() {
+ readonly | _parse_READONLY
+ }
+ _ignore_READONLY_bash() {
+ readonly | _parse_READONLY
+ }
+ _ignore_READONLY_ksh() {
+ readonly | _parse_READONLY
+ }
+ _ignore_READONLY_zsh() {
+ # shellcheck disable=SC3044
+ typeset -pr | _parse_READONLY
+ }
+ _remove_bad_NAMES() {
+ # Do not transfer vars and funcs from env_parallel
+ # shellcheck disable=SC2006
+ _ignore_RO="`_ignore_READONLY`"
+ # shellcheck disable=SC2006
+ _ignore_HARD="`_ignore_HARDCODED`"
+ # To avoid depending on grep dialect, use Perl version of:
+ # grep -Ev '^(...)$' |
+ perl -ne '/^(
+ PARALLEL_ENV|
+ PARALLEL_TMP|
+ _alias_NAMES|
+ _bodies_of_ALIASES|
+ _bodies_of_FUNCTIONS|
+ _bodies_of_VARIABLES|
+ _error_PAR|
+ _function_NAMES|
+ _get_ignored_VARS|
+ _grep_REGEXP|
+ _ignore_HARD|
+ _ignore_HARDCODED|
+ _ignore_READONLY|
+ _ignore_RO|
+ _ignore_UNDERSCORE|
+ _list_alias_BODIES|
+ _list_function_BODIES|
+ _list_variable_VALUES|
+ _make_grep_REGEXP|
+ _names_of_ALIASES|
+ _names_of_FUNCTIONS|
+ _names_of_VARIABLES|
+ _names_of_maybe_FUNCTIONS|
+ _parallel_exit_CODE|
+ _prefix_PARALLEL_ENV|
+ _prefix_PARALLEL_ENV_bash|
+ _remove_bad_NAMES|
+ _remove_readonly|
+ _variable_NAMES|
+ _warning_PAR|
+ _which_PAR)$/x and next;
+ # Filter names matching --env
+ /^'"$_grep_REGEXP"'$/ or next;
+ /^'"$_ignore_UNDERSCORE"'$/ and next;
+ # Remove readonly variables
+ /^'"$_ignore_RO"'$/ and next;
+ /^'"$_ignore_HARD"'$/ and next;
+ print;'
+ }
+ _prefix_PARALLEL_ENV_bash() {
+ # shellcheck disable=SC3044
+ shopt 2>/dev/null |
+ perl -pe 's:\s+off:;: and s/^/shopt -u /;
+ s:\s+on:;: and s/^/shopt -s /;
+ s:;$:&>/dev/null;:';
+ echo 'shopt -s expand_aliases &>/dev/null';
+ }
+
+ _get_ignored_VARS() {
+ perl -e '
+ for(@ARGV){
+ $next_is_env and push @envvar, split/,/, $_;
+ $next_is_env=/^--env$/;
+ }
+ if(grep { /^_$/ } @envvar) {
+ if(not open(IN, "<", "$ENV{HOME}/.parallel/ignored_vars")) {
+ print STDERR "parallel: Error: ",
+ "Run \"parallel --record-env\" in a clean environment first.\n";
+ } else {
+ chomp(@ignored_vars = <IN>);
+ }
+ }
+ if($ENV{PARALLEL_IGNORED_NAMES}) {
+ push @ignored_vars, split/\s+/, $ENV{PARALLEL_IGNORED_NAMES};
+ chomp @ignored_vars;
+ }
+ $vars = join "|",map { quotemeta $_ } @ignored_vars;
+ print $vars ? "($vars)" : "(,,nO,,VaRs,,)";
+ ' -- "$@"
+ }
+
+ # Get the --env variables if set
+ # --env _ should be ignored
+ # and convert a b c to (a|b|c)
+ # If --env not set: Match everything (.*)
+ _make_grep_REGEXP() {
+ perl -e '
+ for(@ARGV){
+ /^_$/ and $next_is_env = 0;
+ $next_is_env and push @envvar, split/,/, $_;
+ $next_is_env = /^--env$/;
+ }
+ $vars = join "|",map { quotemeta $_ } @envvar;
+ print $vars ? "($vars)" : "(.*)";
+ ' -- "$@"
+ }
+ _which_PAR() {
+ # type returns:
+ # ll is an alias for ls -l (in ash)
+ # bash is a tracked alias for /bin/bash
+ # true is a shell builtin (in bash)
+ # myfunc is a function (in bash)
+ # myfunc is a shell function (in zsh)
+ # which is /usr/bin/which (in sh, bash)
+ # which is hashed (/usr/bin/which)
+ # gi is aliased to `grep -i' (in bash)
+ # aliased to `alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
+ # Return 0 if found, 1 otherwise
+ LANG=C type "$@" |
+ perl -pe '$exit += (s/ is an alias for .*// ||
+ s/ is aliased to .*// ||
+ s/ is a function// ||
+ s/ is a shell function// ||
+ s/ is a shell builtin// ||
+ s/.* is hashed .(\S+).$/$1/ ||
+ s/.* is (a tracked alias for )?//);
+ END { exit not $exit }'
+ }
+ _warning_PAR() {
+ echo "env_parallel: Warning: $*" >&2
+ }
+ _error_PAR() {
+ echo "env_parallel: Error: $*" >&2
+ }
+
+ if _which_PAR parallel >/dev/null; then
+ true parallel found in path
+ else
+ # shellcheck disable=SC2016
+ _error_PAR 'parallel must be in $PATH.'
+ return 255
+ fi
+
+ # Grep regexp for vars given by --env
+ # shellcheck disable=SC2006
+ _grep_REGEXP="`_make_grep_REGEXP \"$@\"`"
+ unset _make_grep_REGEXP
+
+ # Deal with --env _
+ # shellcheck disable=SC2006
+ _ignore_UNDERSCORE="`_get_ignored_VARS \"$@\"`"
+ unset _get_ignored_VARS
+
+ # --record-env
+ if perl -e 'exit grep { /^--record-env$/ } @ARGV' -- "$@"; then
+ true skip
+ else
+ (_names_of_ALIASES;
+ _names_of_FUNCTIONS;
+ _names_of_VARIABLES) |
+ cat > "$HOME"/.parallel/ignored_vars
+ return 0
+ fi
+
+ # --session
+ if perl -e 'exit grep { /^--session$/ } @ARGV' -- "$@"; then
+ true skip
+ else
+ # Insert ::: between each level of session
+ # so you can pop off the last ::: at --end-session
+ # shellcheck disable=SC2006
+ PARALLEL_IGNORED_NAMES="`echo \"$PARALLEL_IGNORED_NAMES\";
+ echo :::;
+ (_names_of_ALIASES;
+ _names_of_FUNCTIONS;
+ _names_of_VARIABLES) | perl -ne '
+ BEGIN{
+ map { $ignored_vars{$_}++ }
+ split/\s+/, $ENV{PARALLEL_IGNORED_NAMES};
+ }
+ chomp;
+ for(split/\s+/) {
+ if(not $ignored_vars{$_}) {
+ print $_,\"\\n\";
+ }
+ }
+ '`"
+ export PARALLEL_IGNORED_NAMES
+ return 0
+ fi
+ if perl -e 'exit grep { /^--end.?session$/ } @ARGV' -- "$@"; then
+ true skip
+ else
+ # Pop off last ::: from PARALLEL_IGNORED_NAMES
+ # shellcheck disable=SC2006
+ PARALLEL_IGNORED_NAMES="`perl -e '
+ $ENV{PARALLEL_IGNORED_NAMES} =~ s/(.*):::.*?$/$1/s;
+ print $ENV{PARALLEL_IGNORED_NAMES}
+ '`"
+ return 0
+ fi
+ # Grep alias names
+ # shellcheck disable=SC2006
+ _alias_NAMES="`_names_of_ALIASES | _remove_bad_NAMES | xargs echo`"
+ _list_alias_BODIES="_bodies_of_ALIASES $_alias_NAMES"
+ if [ "$_alias_NAMES" = "" ] ; then
+ # no aliases selected
+ _list_alias_BODIES="true"
+ fi
+ unset _alias_NAMES
+
+ # Grep function names
+ # shellcheck disable=SC2006
+ _function_NAMES="`_names_of_FUNCTIONS | _remove_bad_NAMES | xargs echo`"
+ _list_function_BODIES="_bodies_of_FUNCTIONS $_function_NAMES"
+ if [ "$_function_NAMES" = "" ] ; then
+ # no functions selected
+ _list_function_BODIES="true"
+ fi
+ unset _function_NAMES
+
+ # Grep variable names
+ # shellcheck disable=SC2006
+ _variable_NAMES="`_names_of_VARIABLES | _remove_bad_NAMES | xargs echo`"
+ _list_variable_VALUES="_bodies_of_VARIABLES $_variable_NAMES"
+ if [ "$_variable_NAMES" = "" ] ; then
+ # no variables selected
+ _list_variable_VALUES="true"
+ fi
+ unset _variable_NAMES
+
+ if $_eval_needed ; then
+ # shellcheck disable=SC2006
+ PARALLEL_ENV="`
+ eval $_prefix_PARALLEL_ENV;
+ eval $_list_alias_BODIES;
+ eval $_list_function_BODIES;
+ eval $_list_variable_VALUES;
+ `"
+ else
+ # shellcheck disable=SC2006
+ PARALLEL_ENV="`
+ $_prefix_PARALLEL_ENV;
+ $_list_alias_BODIES;
+ $_list_function_BODIES;
+ $_list_variable_VALUES;
+ `"
+ fi
+ export PARALLEL_ENV
+ # Free up some env space
+ unset _list_alias_BODIES _list_variable_VALUES _list_function_BODIES
+ unset _bodies_of_ALIASES _bodies_of_VARIABLES _bodies_of_FUNCTIONS
+ unset _names_of_ALIASES _names_of_VARIABLES _names_of_FUNCTIONS
+ unset _ignore_HARDCODED _ignore_READONLY _ignore_UNDERSCORE
+ unset _remove_bad_NAMES _grep_REGEXP _parse_READONLY
+ unset _prefix_PARALLEL_ENV
+ unset _ignore_READONLY_sh _ignore_READONLY_bash
+ unset _ignore_READONLY_ksh _ignore_READONLY_zsh
+ unset _ignore_HARDCODED_sh _ignore_HARDCODED_bash
+ unset _ignore_HARDCODED_ksh _ignore_HARDCODED_zsh
+ unset _bodies_of_ALIASES_ksh _bodies_of_ALIASES_sh
+ unset _bodies_of_ALIASES_zsh _bodies_of_FUNCTIONS_bash
+ unset _bodies_of_FUNCTIONS_ksh _bodies_of_FUNCTIONS_sh
+ unset _bodies_of_FUNCTIONS_zsh _bodies_of_VARIABLES_bash
+ unset _bodies_of_VARIABLES_ksh _bodies_of_VARIABLES_sh
+ unset _bodies_of_VARIABLES_zsh
+ unset _names_of_ALIASES _names_of_ALIASES_bash
+ unset _names_of_ALIASES_ksh _names_of_ALIASES_sh
+ unset _names_of_ALIASES_zsh _names_of_FUNCTIONS
+ unset _names_of_FUNCTIONS_bash _names_of_FUNCTIONS_ksh
+ unset _names_of_FUNCTIONS_sh _names_of_FUNCTIONS_zsh
+ unset _names_of_VARIABLES _names_of_VARIABLES_bash
+ unset _names_of_VARIABLES_ksh _names_of_VARIABLES_sh
+ unset _names_of_VARIABLES_zsh _names_of_maybe_FUNCTIONS
+
+ # Test if environment is too big by running 'true'
+ # shellcheck disable=SC2006,SC2092
+ if `_which_PAR true` >/dev/null 2>/dev/null ; then
+ parallel "$@"
+ _parallel_exit_CODE=$?
+ # Clean up variables/functions
+ unset PARALLEL_ENV
+ unset _which_PAR _which_TRUE
+ unset _warning_PAR _error_PAR
+ # Unset _parallel_exit_CODE before return
+ eval "unset _parallel_exit_CODE; return $_parallel_exit_CODE"
+ else
+ unset PARALLEL_ENV;
+ _error_PAR "Your environment is too big."
+ _error_PAR "You can try 3 different approaches:"
+ _error_PAR "1. Run 'env_parallel --session' before you set"
+ _error_PAR " variables or define functions."
+ _error_PAR "2. Use --env and only mention the names to copy."
+ _error_PAR "3. Try running this in a clean environment once:"
+ _error_PAR " env_parallel --record-env"
+ _error_PAR " And then use '--env _'"
+ _error_PAR "For details see: man env_parallel"
+ return 255
+ fi
+}
+
+parset() {
+ _parset_PARALLEL_PRG=parallel
+ _parset_main "$@"
+}
+
+env_parset() {
+ _parset_PARALLEL_PRG=env_parallel
+ _parset_main "$@"
+}
+
+_parset_main() {
+ # If $1 contains ',' or space:
+ # Split on , to get the destination variable names
+ # If $1 is a single destination variable name:
+ # Treat it as the name of an array
+ #
+ # # Create array named myvar
+ # parset myvar echo ::: {1..10}
+ # echo ${myvar[5]}
+ #
+ # # Put output into $var_a $var_b $var_c
+ # varnames=(var_a var_b var_c)
+ # parset "${varnames[*]}" echo ::: {1..3}
+ # echo $var_c
+ #
+ # # Put output into $var_a4 $var_b4 $var_c4
+ # parset "var_a4 var_b4 var_c4" echo ::: {1..3}
+ # echo $var_c4
+
+ _parset_NAME="$1"
+ if [ "$_parset_NAME" = "" ] ; then
+ echo parset: Error: No destination variable given. >&2
+ echo parset: Error: Try: >&2
+ echo parset: Error: ' ' parset myarray echo ::: foo bar >&2
+ return 255
+ fi
+ if [ "$_parset_NAME" = "--help" ] ; then
+ echo parset: Error: Usage: >&2
+ echo parset: Error: ' ' parset varname GNU Parallel options and command >&2
+ echo
+ parallel --help
+ return 255
+ fi
+ if [ "$_parset_NAME" = "--version" ] ; then
+ # shellcheck disable=SC2006
+ echo "parset 20240222 (GNU parallel `parallel --minversion 1`)"
+ echo "Copyright (C) 2007-2024 Ole Tange, http://ole.tange.dk and Free Software"
+ echo "Foundation, Inc."
+ echo "License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>"
+ echo "This is free software: you are free to change and redistribute it."
+ echo "GNU parallel comes with no warranty."
+ echo
+ echo "Web site: https://www.gnu.org/software/parallel"
+ echo
+ echo "When using programs that use GNU Parallel to process data for publication"
+ echo "please cite as described in 'parallel --citation'."
+ echo
+ return 255
+ fi
+ shift
+
+ # Bash: declare -A myassoc=( )
+ # Zsh: typeset -A myassoc=( )
+ # Ksh: typeset -A myassoc=( )
+ # shellcheck disable=SC2039,SC2169,SC3044
+ if (typeset -p "$_parset_NAME" 2>/dev/null; echo) |
+ perl -ne 'exit not (/^declare[^=]+-A|^typeset[^=]+-A/)' ; then
+ # This is an associative array
+ # shellcheck disable=SC2006
+ eval "`$_parset_PARALLEL_PRG -k --_parset assoc,"$_parset_NAME" "$@"`"
+ # The eval returns the function!
+ else
+ # This is a normal array or a list of variable names
+ # shellcheck disable=SC2006
+ eval "`$_parset_PARALLEL_PRG -k --_parset var,"$_parset_NAME" "$@"`"
+ # The eval returns the function!
+ fi
+}
diff --git a/src/env_parallel.tcsh b/src/env_parallel.tcsh
new file mode 100755
index 0000000..dcb7a0b
--- /dev/null
+++ b/src/env_parallel.tcsh
@@ -0,0 +1,142 @@
+#!/usr/bin/env tcsh
+
+# This file must be sourced in tcsh:
+#
+# source `which env_parallel.tcsh`
+#
+# after which 'env_parallel' works
+#
+#
+# Copyright (C) 2016-2024 Ole Tange, http://ole.tange.dk and 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/>
+# or write to the Free Software Foundation, Inc., 51 Franklin St,
+# Fifth Floor, Boston, MA 02110-1301 USA
+#
+# SPDX-FileCopyrightText: 2021-2024 Ole Tange, http://ole.tange.dk and Free Software and Foundation, Inc.
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+set _parallel_exit_CODE=0
+if ("`alias env_parallel`" == '' || ! $?PARALLEL_CSH) then
+ # Activate alias
+ alias env_parallel '(setenv PARALLEL_CSH "\!*"; source `which env_parallel.csh`)'
+else
+ # Get the --env variables if set
+ # --env _ should be ignored
+ # and convert a b c to (a|b|c)
+ # If --env not set: Match everything (.*)
+
+ # simple 'tempfile': Return nonexisting filename: /tmp/parXXXXX
+ alias _tempfile 'perl -e do\{\$t\=\"/tmp/par\".join\"\",map\{\(0..9,\"a\"..\"z\",\"A\"..\"Z\"\)\[rand\(62\)\]\}\(1..5\)\;\}while\(-e\$t\)\;print\"\$t\\n\"'
+ set _tMpscRIpt=`_tempfile`
+
+ cat <<'EOF' > $_tMpscRIpt
+ #!/usr/bin/perl
+
+ for(@ARGV){
+ /^_$/ and $next_is_env = 0;
+ $next_is_env and push @envvar, split/,/, $_;
+ $next_is_env = /^--env$/;
+ }
+ $vars = join "|",map { quotemeta $_ } @envvar;
+ print $vars ? "($vars)" : "(.*)";
+'EOF'
+ set _grep_REGEXP="`perl $_tMpscRIpt -- $PARALLEL_CSH`"
+
+ # Deal with --env _
+ cat <<'EOF' > $_tMpscRIpt
+ #!/usr/bin/perl
+
+ for(@ARGV){
+ $next_is_env and push @envvar, split/,/, $_;
+ $next_is_env=/^--env$/;
+ }
+ if(grep { /^_$/ } @envvar) {
+ if(not open(IN, "<", "$ENV{HOME}/.parallel/ignored_vars")) {
+ print STDERR "parallel: Error: ",
+ "Run \"parallel --record-env\" in a clean environment first.\n";
+ } else {
+ chomp(@ignored_vars = <IN>);
+ $vars = join "|",map { quotemeta $_ } @ignored_vars;
+ print $vars ? "($vars)" : "(,,nO,,VaRs,,)";
+ }
+ }
+'EOF'
+ set _ignore_UNDERSCORE="`perl $_tMpscRIpt -- $PARALLEL_CSH`"
+ rm $_tMpscRIpt
+
+ # Get the scalar and array variable names
+ set _vARnAmES=(`set | perl -ne 's/\s.*//; /^(#|_|killring|prompt2|command|PARALLEL_ENV|PARALLEL_TMP)$/ and next; /^'"$_grep_REGEXP"'$/ or next; /^'"$_ignore_UNDERSCORE"'$/ and next; print'`)
+
+ # Make a tmpfile for the variable definitions
+ set _tMpvARfILe=`_tempfile`
+ touch $_tMpvARfILe
+ # Make a tmpfile for the variable definitions + alias
+ set _tMpaLLfILe=`_tempfile`
+ foreach _vARnAmE ($_vARnAmES);
+ # These 3 lines break in csh ver. 20110502-3
+ # if not defined: next
+ eval if'(! $?'$_vARnAmE') continue'
+ # if $#myvar <= 1 echo scalar_myvar=$var
+ eval if'(${#'$_vARnAmE'} <= 1) echo scalar_'$_vARnAmE'='\"\$$_vARnAmE\" >> $_tMpvARfILe;
+ # if $#myvar > 1 echo array_myvar=$var
+ eval if'(${#'$_vARnAmE'} > 1) echo array_'$_vARnAmE'="$'$_vARnAmE'"' >> $_tMpvARfILe;
+ end
+ unset _vARnAmE _vARnAmES
+ # shell quote variables (--plain needed due to ignore if $PARALLEL is set)
+ # Convert 'scalar_myvar=...' to 'set myvar=...'
+ # Convert 'array_myvar=...' to 'set array=(...)'
+ cat $_tMpvARfILe | parallel --plain --shellquote | perl -pe 's/^scalar_(\S+).=/set $1=/ or s/^array_(\S+).=(.*)/set $1=($2)/ && s/\\ / /g;' > $_tMpaLLfILe
+ # Cleanup
+ rm $_tMpvARfILe; unset _tMpvARfILe
+
+# ALIAS TO EXPORT ALIASES:
+
+# Quote ' by putting it inside "
+# s/'/'"'"'/g;
+# ' => \047 " => \042
+# s/\047/\047\042\047\042\047/g;
+# Quoted: s/\\047/\\047\\042\\047\\042\\047/g\;
+
+# Remove () from second column
+# s/^(\S+)(\s+)\((.*)\)/\1\2\3/;
+# Quoted: s/\^\(\\S+\)\(\\s+\)\\\(\(.\*\)\\\)/\\1\\2\\3/\;
+
+# Add ' around second column
+# s/^(\S+)(\s+)(.*)/\1\2'\3'/
+# \047 => '
+# s/^(\S+)(\s+)(.*)/\1\2\047\3\047/;
+# Quoted: s/\^\(\\S+\)\(\\s+\)\(.\*\)/\\1\\2\\047\\3\\047/\;
+
+# Quote ! as \!
+# s/\!/\\\!/g;
+# Quoted: s/\\\!/\\\\\\\!/g;
+
+# Prepend with "\nalias "
+# s/^/\001alias /;
+# Quoted: s/\^/\\001alias\ /\;
+ alias | \
+ perl -ne '/^'"$_grep_REGEXP"'/ or next; /^'"$_ignore_UNDERSCORE"'[^_a-zA-Z]/ and next; print' | \
+ perl -pe s/\\047/\\047\\042\\047\\042\\047/g\;s/\^\(\\S+\)\(\\s+\)\\\(\(.\*\)\\\)/\\1\\2\\3/\;s/\^\(\\S+\)\(\\s+\)\(.\*\)/\\1\\2\\047\\3\\047/\;s/\^/\\001alias\ /\;s/\\\!/\\\\\\\!/g >> $_tMpaLLfILe
+
+ setenv PARALLEL_ENV "`cat $_tMpaLLfILe; rm $_tMpaLLfILe`";
+ unset _tMpaLLfILe;
+ # Use $PARALLEL_CSH set in calling alias
+ parallel
+ set _parallel_exit_CODE=$status
+ setenv PARALLEL_ENV
+ setenv PARALLEL_CSH
+endif
+(exit $_parallel_exit_CODE)
diff --git a/src/env_parallel.zsh b/src/env_parallel.zsh
new file mode 100755
index 0000000..674d8e6
--- /dev/null
+++ b/src/env_parallel.zsh
@@ -0,0 +1,636 @@
+#!/usr/bin/env zsh
+
+# This file must be sourced in sh/ash/dash/bash/ksh/mksh/zsh:
+#
+# . env_parallel.sh
+# source env_parallel.ash
+# source env_parallel.dash
+# source env_parallel.bash
+# source env_parallel.ksh
+# source env_parallel.mksh
+# source env_parallel.zsh
+#
+# after which 'env_parallel' works
+#
+#
+# Copyright (C) 2016-2024 Ole Tange, http://ole.tange.dk and 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/>
+# or write to the Free Software Foundation, Inc., 51 Franklin St,
+# Fifth Floor, Boston, MA 02110-1301 USA
+#
+# SPDX-FileCopyrightText: 2021-2024 Ole Tange, http://ole.tange.dk and Free Software and Foundation, Inc.
+# SPDX-License-Identifier: GPL-3.0-or-later
+# shellcheck disable=SC2006
+
+env_parallel() {
+ # env_parallel.{sh,ash,dash,bash,ksh,mksh,zsh}
+
+ # Check shell dialect
+ if [ -n "$BASH_VERSION" ]; then
+ _shell_DIALECT=bash
+ _eval_needed=false
+ _prefix_PARALLEL_ENV=_prefix_PARALLEL_ENV_bash
+ elif [ -n "$ZSH_VERSION" ]; then
+ _shell_DIALECT=zsh
+ _eval_needed=true
+ _prefix_PARALLEL_ENV=false
+ elif [ -n "$KSH_VERSION" ]; then
+ _shell_DIALECT=ksh
+ _eval_needed=false
+ _prefix_PARALLEL_ENV=false
+ else
+ # Dash/ash - can these be detected better?
+ _shell_DIALECT="sh"
+ _eval_needed=false
+ _prefix_PARALLEL_ENV=false
+ fi
+ _names_of_ALIASES() {
+ _names_of_ALIASES_$_shell_DIALECT
+ }
+ _names_of_ALIASES_sh() {
+ # alias fails on Unixware 5
+ for _i in `alias 2>/dev/null | perl -ne 's/^alias //;s/^(\S+)=.*/$1/ && print' 2>/dev/null`; do
+ # Check if this name really is an alias
+ # or just part of a multiline alias definition
+ if alias "$_i" >/dev/null 2>/dev/null; then
+ echo "$_i"
+ fi
+ done
+ }
+ _names_of_ALIASES_bash() {
+ # No aliases will return false. This error should be ignored.
+ # shellcheck disable=SC3044
+ compgen -a || true
+ }
+ _names_of_ALIASES_ksh() {
+ alias | perl -pe 's/=.*//'
+ }
+ _names_of_ALIASES_zsh() {
+ # shellcheck disable=SC2086,SC2296
+ print -l ${(k)aliases}
+ }
+ _bodies_of_ALIASES() {
+ _bodies_of_ALIASES_$_shell_DIALECT "$@"
+ }
+ _bodies_of_ALIASES_sh() {
+ # alias may return:
+ # myalias='definition' (GNU/Linux ash)
+ # alias myalias='definition' (FreeBSD ash)
+ # so remove 'alias ' from first line
+ for _i in "$@"; do
+ echo 'alias '"`alias "$_i" | perl -pe '1..1 and s/^alias //'`"
+ done
+ }
+ _bodies_of_ALIASES_bash() {
+ # shellcheck disable=SC3043
+ local _i
+ for _i in "$@"; do
+ # shellcheck disable=SC2046
+ if [ $(alias "$_i" | wc -l) = 1 ] ; then
+ true Alias is a single line. Good.
+ else
+ _warning_PAR "Alias '$_i' contains newline."
+ _warning_PAR "Make sure the command has at least one newline after '$_i'."
+ _warning_PAR "See BUGS in 'man env_parallel'."
+ fi
+ done
+ alias "$@"
+ }
+ _bodies_of_ALIASES_ksh() {
+ alias "$@" | perl -pe 's/^/alias /;
+ sub warning { print STDERR "env_parallel: Warning: @_\n"; }
+ if(/^alias (\S+)=\$.*\\n/) {
+ warning("Alias \"$1\" contains newline.");
+ warning("Make sure the command has at least one newline after \"$1\".");
+ warning("See BUGS in \"man env_parallel\".");
+ }'
+
+ }
+ _bodies_of_ALIASES_zsh() {
+ # shellcheck disable=SC3043
+ local _i
+ for _i in "$@"; do
+ echo 'alias '"$(alias "$_i")"
+ done
+ }
+ _names_of_FUNCTIONS() {
+ _names_of_FUNCTIONS_$_shell_DIALECT
+ }
+ _names_of_FUNCTIONS_bash() {
+ # shellcheck disable=SC3044
+ compgen -A function
+ }
+ _names_of_maybe_FUNCTIONS() {
+ set | perl -ne '/^([A-Z_0-9]+)\s*\(\)\s*\{?$/i and print "$1\n"'
+ }
+ _names_of_FUNCTIONS_sh() {
+ # myfunc is a function
+ # shellcheck disable=SC2046
+ LANG=C type `_names_of_maybe_FUNCTIONS` |
+ perl -ne '/^(\S+) is a function$/ and not $seen{$1}++ and print "$1\n"'
+ }
+ _names_of_FUNCTIONS_ksh() {
+ # shellcheck disable=SC3044
+ typeset +f | perl -pe 's/\(\).*//; s/ .*//;'
+ }
+ _names_of_FUNCTIONS_zsh() {
+ # shellcheck disable=SC2086,SC2296
+ print -l ${(k)functions}
+ }
+ _bodies_of_FUNCTIONS() {
+ _bodies_of_FUNCTIONS_$_shell_DIALECT "$@"
+ }
+ _bodies_of_FUNCTIONS_sh() {
+ LANG=C type "$@" | perl -ne '/^(\S+) is a function$/ or print'
+ }
+ _bodies_of_FUNCTIONS_bash() {
+ # shellcheck disable=SC3044
+ typeset -f "$@"
+ }
+ _bodies_of_FUNCTIONS_ksh() {
+ functions "$@"
+ }
+ _bodies_of_FUNCTIONS_zsh() {
+ # shellcheck disable=SC3044
+ typeset -f "$@"
+ }
+ _names_of_VARIABLES() {
+ _names_of_VARIABLES_$_shell_DIALECT
+ }
+ _names_of_VARIABLES_sh() {
+ # This may screw up if variables contain \n and =
+ set | perl -ne 's/^(\S+?)=.*/$1/ and print;'
+ }
+ _names_of_VARIABLES_bash() {
+ # shellcheck disable=SC3044
+ compgen -A variable
+ }
+ _names_of_VARIABLES_ksh() {
+ # shellcheck disable=SC3044
+ typeset +p |
+ perl -pe 's/^(type)?set( [-+][a-zA-Z0-9]*)* //; s/(\[\d+\])?=.*//' |
+ uniq
+ }
+ _names_of_VARIABLES_zsh() {
+ # shellcheck disable=SC2086,SC2296
+ print -l ${(k)parameters}
+ }
+ _bodies_of_VARIABLES() {
+ _bodies_of_VARIABLES_$_shell_DIALECT "$@"
+ }
+ _bodies_of_VARIABLES_sh() {
+ # Crappy typeset -p
+ for _i in "$@"
+ do
+ perl -e 'print @ARGV' "$_i="
+ eval echo "\"\$$_i\"" | perl -e '$/=undef; $a=<>; chop($a); print $a' |
+ perl -pe 's/[\002-\011\013-\032\\\#\?\`\(\)\{\}\[\]\^\*\<\=\>\~\|\; \"\!\$\&\202-\377]/\\$&/go;'"s/'/\\\'/g; s/[\n]/'\\n'/go;";
+ echo
+ done
+ }
+ _bodies_of_VARIABLES_bash() {
+ # shellcheck disable=SC3044
+ typeset -p "$@"
+ }
+ _bodies_of_VARIABLES_ksh() {
+ # shellcheck disable=SC3044
+ typeset -p "$@"
+ }
+ _bodies_of_VARIABLES_zsh() {
+ # shellcheck disable=SC3044
+ typeset -p "$@"
+ }
+ _ignore_HARDCODED() {
+ _ignore_HARDCODED_$_shell_DIALECT
+ }
+ _ignore_HARDCODED_sh() {
+ # These names cannot be detected
+ echo '(_|TIMEOUT|IFS)'
+ }
+ _ignore_HARDCODED_bash() {
+ # Copying $RANDOM will cause it not to be random
+ # The rest cannot be detected as read-only
+ echo '(RANDOM|_|TIMEOUT|GROUPS|FUNCNAME|DIRSTACK|PIPESTATUS|USERNAME|BASHPID|BASH_[A-Z_]+)'
+ }
+ _ignore_HARDCODED_ksh() {
+ # These names cannot be detected
+ echo '(_|TIMEOUT|IFS)'
+ }
+ _ignore_HARDCODED_zsh() {
+ # These names cannot be detected
+ echo '([-\?\#\!\$\*\@\_0]|zsh_eval_context|ZSH_EVAL_CONTEXT|LINENO|IFS|commands|functions|options|aliases|EUID|EGID|UID|GID|dis_patchars|patchars|terminfo|galiases|keymaps|parameters|jobdirs|dirstack|functrace|funcsourcetrace|zsh_scheduled_events|dis_aliases|dis_reswords|dis_saliases|modules|reswords|saliases|widgets|userdirs|historywords|nameddirs|termcap|dis_builtins|dis_functions|jobtexts|funcfiletrace|dis_galiases|builtins|history|jobstates|funcstack|run-help)'
+ }
+ _ignore_READONLY() {
+ _ignore_READONLY_$_shell_DIALECT
+ }
+ _parse_READONLY() {
+ # shellcheck disable=SC1078,SC1079,SC2026
+ perl -e '@r = map {
+ chomp;
+ # sh on UnixWare: readonly TIMEOUT
+ # ash: readonly var='val'
+ # ksh: var='val'
+ # mksh: PIPESTATUS[0]
+ s/^(readonly )?([^=\[ ]*?)(\[\d+\])?(=.*|)$/$2/ or
+ # bash: declare -ar BASH_VERSINFO=([0]="4" [1]="4")
+ # zsh: typeset -r var='val'
+ s/^\S+\s+\S+\s+(\S[^=]*)(=.*|$)/$1/;
+ $_ } <>;
+ $vars = join "|",map { quotemeta $_ } @r;
+ print $vars ? "($vars)" : "(,,nO,,VaRs,,)";
+ '
+ }
+ _ignore_READONLY_sh() {
+ readonly | _parse_READONLY
+ }
+ _ignore_READONLY_bash() {
+ readonly | _parse_READONLY
+ }
+ _ignore_READONLY_ksh() {
+ readonly | _parse_READONLY
+ }
+ _ignore_READONLY_zsh() {
+ # shellcheck disable=SC3044
+ typeset -pr | _parse_READONLY
+ }
+ _remove_bad_NAMES() {
+ # Do not transfer vars and funcs from env_parallel
+ # shellcheck disable=SC2006
+ _ignore_RO="`_ignore_READONLY`"
+ # shellcheck disable=SC2006
+ _ignore_HARD="`_ignore_HARDCODED`"
+ # To avoid depending on grep dialect, use Perl version of:
+ # grep -Ev '^(...)$' |
+ perl -ne '/^(
+ PARALLEL_ENV|
+ PARALLEL_TMP|
+ _alias_NAMES|
+ _bodies_of_ALIASES|
+ _bodies_of_FUNCTIONS|
+ _bodies_of_VARIABLES|
+ _error_PAR|
+ _function_NAMES|
+ _get_ignored_VARS|
+ _grep_REGEXP|
+ _ignore_HARD|
+ _ignore_HARDCODED|
+ _ignore_READONLY|
+ _ignore_RO|
+ _ignore_UNDERSCORE|
+ _list_alias_BODIES|
+ _list_function_BODIES|
+ _list_variable_VALUES|
+ _make_grep_REGEXP|
+ _names_of_ALIASES|
+ _names_of_FUNCTIONS|
+ _names_of_VARIABLES|
+ _names_of_maybe_FUNCTIONS|
+ _parallel_exit_CODE|
+ _prefix_PARALLEL_ENV|
+ _prefix_PARALLEL_ENV_bash|
+ _remove_bad_NAMES|
+ _remove_readonly|
+ _variable_NAMES|
+ _warning_PAR|
+ _which_PAR)$/x and next;
+ # Filter names matching --env
+ /^'"$_grep_REGEXP"'$/ or next;
+ /^'"$_ignore_UNDERSCORE"'$/ and next;
+ # Remove readonly variables
+ /^'"$_ignore_RO"'$/ and next;
+ /^'"$_ignore_HARD"'$/ and next;
+ print;'
+ }
+ _prefix_PARALLEL_ENV_bash() {
+ # shellcheck disable=SC3044
+ shopt 2>/dev/null |
+ perl -pe 's:\s+off:;: and s/^/shopt -u /;
+ s:\s+on:;: and s/^/shopt -s /;
+ s:;$:&>/dev/null;:';
+ echo 'shopt -s expand_aliases &>/dev/null';
+ }
+
+ _get_ignored_VARS() {
+ perl -e '
+ for(@ARGV){
+ $next_is_env and push @envvar, split/,/, $_;
+ $next_is_env=/^--env$/;
+ }
+ if(grep { /^_$/ } @envvar) {
+ if(not open(IN, "<", "$ENV{HOME}/.parallel/ignored_vars")) {
+ print STDERR "parallel: Error: ",
+ "Run \"parallel --record-env\" in a clean environment first.\n";
+ } else {
+ chomp(@ignored_vars = <IN>);
+ }
+ }
+ if($ENV{PARALLEL_IGNORED_NAMES}) {
+ push @ignored_vars, split/\s+/, $ENV{PARALLEL_IGNORED_NAMES};
+ chomp @ignored_vars;
+ }
+ $vars = join "|",map { quotemeta $_ } @ignored_vars;
+ print $vars ? "($vars)" : "(,,nO,,VaRs,,)";
+ ' -- "$@"
+ }
+
+ # Get the --env variables if set
+ # --env _ should be ignored
+ # and convert a b c to (a|b|c)
+ # If --env not set: Match everything (.*)
+ _make_grep_REGEXP() {
+ perl -e '
+ for(@ARGV){
+ /^_$/ and $next_is_env = 0;
+ $next_is_env and push @envvar, split/,/, $_;
+ $next_is_env = /^--env$/;
+ }
+ $vars = join "|",map { quotemeta $_ } @envvar;
+ print $vars ? "($vars)" : "(.*)";
+ ' -- "$@"
+ }
+ _which_PAR() {
+ # type returns:
+ # ll is an alias for ls -l (in ash)
+ # bash is a tracked alias for /bin/bash
+ # true is a shell builtin (in bash)
+ # myfunc is a function (in bash)
+ # myfunc is a shell function (in zsh)
+ # which is /usr/bin/which (in sh, bash)
+ # which is hashed (/usr/bin/which)
+ # gi is aliased to `grep -i' (in bash)
+ # aliased to `alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
+ # Return 0 if found, 1 otherwise
+ LANG=C type "$@" |
+ perl -pe '$exit += (s/ is an alias for .*// ||
+ s/ is aliased to .*// ||
+ s/ is a function// ||
+ s/ is a shell function// ||
+ s/ is a shell builtin// ||
+ s/.* is hashed .(\S+).$/$1/ ||
+ s/.* is (a tracked alias for )?//);
+ END { exit not $exit }'
+ }
+ _warning_PAR() {
+ echo "env_parallel: Warning: $*" >&2
+ }
+ _error_PAR() {
+ echo "env_parallel: Error: $*" >&2
+ }
+
+ if _which_PAR parallel >/dev/null; then
+ true parallel found in path
+ else
+ # shellcheck disable=SC2016
+ _error_PAR 'parallel must be in $PATH.'
+ return 255
+ fi
+
+ # Grep regexp for vars given by --env
+ # shellcheck disable=SC2006
+ _grep_REGEXP="`_make_grep_REGEXP \"$@\"`"
+ unset _make_grep_REGEXP
+
+ # Deal with --env _
+ # shellcheck disable=SC2006
+ _ignore_UNDERSCORE="`_get_ignored_VARS \"$@\"`"
+ unset _get_ignored_VARS
+
+ # --record-env
+ if perl -e 'exit grep { /^--record-env$/ } @ARGV' -- "$@"; then
+ true skip
+ else
+ (_names_of_ALIASES;
+ _names_of_FUNCTIONS;
+ _names_of_VARIABLES) |
+ cat > "$HOME"/.parallel/ignored_vars
+ return 0
+ fi
+
+ # --session
+ if perl -e 'exit grep { /^--session$/ } @ARGV' -- "$@"; then
+ true skip
+ else
+ # Insert ::: between each level of session
+ # so you can pop off the last ::: at --end-session
+ # shellcheck disable=SC2006
+ PARALLEL_IGNORED_NAMES="`echo \"$PARALLEL_IGNORED_NAMES\";
+ echo :::;
+ (_names_of_ALIASES;
+ _names_of_FUNCTIONS;
+ _names_of_VARIABLES) | perl -ne '
+ BEGIN{
+ map { $ignored_vars{$_}++ }
+ split/\s+/, $ENV{PARALLEL_IGNORED_NAMES};
+ }
+ chomp;
+ for(split/\s+/) {
+ if(not $ignored_vars{$_}) {
+ print $_,\"\\n\";
+ }
+ }
+ '`"
+ export PARALLEL_IGNORED_NAMES
+ return 0
+ fi
+ if perl -e 'exit grep { /^--end.?session$/ } @ARGV' -- "$@"; then
+ true skip
+ else
+ # Pop off last ::: from PARALLEL_IGNORED_NAMES
+ # shellcheck disable=SC2006
+ PARALLEL_IGNORED_NAMES="`perl -e '
+ $ENV{PARALLEL_IGNORED_NAMES} =~ s/(.*):::.*?$/$1/s;
+ print $ENV{PARALLEL_IGNORED_NAMES}
+ '`"
+ return 0
+ fi
+ # Grep alias names
+ # shellcheck disable=SC2006
+ _alias_NAMES="`_names_of_ALIASES | _remove_bad_NAMES | xargs echo`"
+ _list_alias_BODIES="_bodies_of_ALIASES $_alias_NAMES"
+ if [ "$_alias_NAMES" = "" ] ; then
+ # no aliases selected
+ _list_alias_BODIES="true"
+ fi
+ unset _alias_NAMES
+
+ # Grep function names
+ # shellcheck disable=SC2006
+ _function_NAMES="`_names_of_FUNCTIONS | _remove_bad_NAMES | xargs echo`"
+ _list_function_BODIES="_bodies_of_FUNCTIONS $_function_NAMES"
+ if [ "$_function_NAMES" = "" ] ; then
+ # no functions selected
+ _list_function_BODIES="true"
+ fi
+ unset _function_NAMES
+
+ # Grep variable names
+ # shellcheck disable=SC2006
+ _variable_NAMES="`_names_of_VARIABLES | _remove_bad_NAMES | xargs echo`"
+ _list_variable_VALUES="_bodies_of_VARIABLES $_variable_NAMES"
+ if [ "$_variable_NAMES" = "" ] ; then
+ # no variables selected
+ _list_variable_VALUES="true"
+ fi
+ unset _variable_NAMES
+
+ if $_eval_needed ; then
+ # shellcheck disable=SC2006
+ PARALLEL_ENV="`
+ eval $_prefix_PARALLEL_ENV;
+ eval $_list_alias_BODIES;
+ eval $_list_function_BODIES;
+ eval $_list_variable_VALUES;
+ `"
+ else
+ # shellcheck disable=SC2006
+ PARALLEL_ENV="`
+ $_prefix_PARALLEL_ENV;
+ $_list_alias_BODIES;
+ $_list_function_BODIES;
+ $_list_variable_VALUES;
+ `"
+ fi
+ export PARALLEL_ENV
+ # Free up some env space
+ unset _list_alias_BODIES _list_variable_VALUES _list_function_BODIES
+ unset _bodies_of_ALIASES _bodies_of_VARIABLES _bodies_of_FUNCTIONS
+ unset _names_of_ALIASES _names_of_VARIABLES _names_of_FUNCTIONS
+ unset _ignore_HARDCODED _ignore_READONLY _ignore_UNDERSCORE
+ unset _remove_bad_NAMES _grep_REGEXP _parse_READONLY
+ unset _prefix_PARALLEL_ENV
+ unset _ignore_READONLY_sh _ignore_READONLY_bash
+ unset _ignore_READONLY_ksh _ignore_READONLY_zsh
+ unset _ignore_HARDCODED_sh _ignore_HARDCODED_bash
+ unset _ignore_HARDCODED_ksh _ignore_HARDCODED_zsh
+ unset _bodies_of_ALIASES_ksh _bodies_of_ALIASES_sh
+ unset _bodies_of_ALIASES_zsh _bodies_of_FUNCTIONS_bash
+ unset _bodies_of_FUNCTIONS_ksh _bodies_of_FUNCTIONS_sh
+ unset _bodies_of_FUNCTIONS_zsh _bodies_of_VARIABLES_bash
+ unset _bodies_of_VARIABLES_ksh _bodies_of_VARIABLES_sh
+ unset _bodies_of_VARIABLES_zsh
+ unset _names_of_ALIASES _names_of_ALIASES_bash
+ unset _names_of_ALIASES_ksh _names_of_ALIASES_sh
+ unset _names_of_ALIASES_zsh _names_of_FUNCTIONS
+ unset _names_of_FUNCTIONS_bash _names_of_FUNCTIONS_ksh
+ unset _names_of_FUNCTIONS_sh _names_of_FUNCTIONS_zsh
+ unset _names_of_VARIABLES _names_of_VARIABLES_bash
+ unset _names_of_VARIABLES_ksh _names_of_VARIABLES_sh
+ unset _names_of_VARIABLES_zsh _names_of_maybe_FUNCTIONS
+
+ # Test if environment is too big by running 'true'
+ # shellcheck disable=SC2006,SC2092
+ if `_which_PAR true` >/dev/null 2>/dev/null ; then
+ parallel "$@"
+ _parallel_exit_CODE=$?
+ # Clean up variables/functions
+ unset PARALLEL_ENV
+ unset _which_PAR _which_TRUE
+ unset _warning_PAR _error_PAR
+ # Unset _parallel_exit_CODE before return
+ eval "unset _parallel_exit_CODE; return $_parallel_exit_CODE"
+ else
+ unset PARALLEL_ENV;
+ _error_PAR "Your environment is too big."
+ _error_PAR "You can try 3 different approaches:"
+ _error_PAR "1. Run 'env_parallel --session' before you set"
+ _error_PAR " variables or define functions."
+ _error_PAR "2. Use --env and only mention the names to copy."
+ _error_PAR "3. Try running this in a clean environment once:"
+ _error_PAR " env_parallel --record-env"
+ _error_PAR " And then use '--env _'"
+ _error_PAR "For details see: man env_parallel"
+ return 255
+ fi
+}
+
+parset() {
+ _parset_PARALLEL_PRG=parallel
+ _parset_main "$@"
+}
+
+env_parset() {
+ _parset_PARALLEL_PRG=env_parallel
+ _parset_main "$@"
+}
+
+_parset_main() {
+ # If $1 contains ',' or space:
+ # Split on , to get the destination variable names
+ # If $1 is a single destination variable name:
+ # Treat it as the name of an array
+ #
+ # # Create array named myvar
+ # parset myvar echo ::: {1..10}
+ # echo ${myvar[5]}
+ #
+ # # Put output into $var_a $var_b $var_c
+ # varnames=(var_a var_b var_c)
+ # parset "${varnames[*]}" echo ::: {1..3}
+ # echo $var_c
+ #
+ # # Put output into $var_a4 $var_b4 $var_c4
+ # parset "var_a4 var_b4 var_c4" echo ::: {1..3}
+ # echo $var_c4
+
+ _parset_NAME="$1"
+ if [ "$_parset_NAME" = "" ] ; then
+ echo parset: Error: No destination variable given. >&2
+ echo parset: Error: Try: >&2
+ echo parset: Error: ' ' parset myarray echo ::: foo bar >&2
+ return 255
+ fi
+ if [ "$_parset_NAME" = "--help" ] ; then
+ echo parset: Error: Usage: >&2
+ echo parset: Error: ' ' parset varname GNU Parallel options and command >&2
+ echo
+ parallel --help
+ return 255
+ fi
+ if [ "$_parset_NAME" = "--version" ] ; then
+ # shellcheck disable=SC2006
+ echo "parset 20240222 (GNU parallel `parallel --minversion 1`)"
+ echo "Copyright (C) 2007-2024 Ole Tange, http://ole.tange.dk and Free Software"
+ echo "Foundation, Inc."
+ echo "License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>"
+ echo "This is free software: you are free to change and redistribute it."
+ echo "GNU parallel comes with no warranty."
+ echo
+ echo "Web site: https://www.gnu.org/software/parallel"
+ echo
+ echo "When using programs that use GNU Parallel to process data for publication"
+ echo "please cite as described in 'parallel --citation'."
+ echo
+ return 255
+ fi
+ shift
+
+ # Bash: declare -A myassoc=( )
+ # Zsh: typeset -A myassoc=( )
+ # Ksh: typeset -A myassoc=( )
+ # shellcheck disable=SC2039,SC2169,SC3044
+ if (typeset -p "$_parset_NAME" 2>/dev/null; echo) |
+ perl -ne 'exit not (/^declare[^=]+-A|^typeset[^=]+-A/)' ; then
+ # This is an associative array
+ # shellcheck disable=SC2006
+ eval "`$_parset_PARALLEL_PRG -k --_parset assoc,"$_parset_NAME" "$@"`"
+ # The eval returns the function!
+ else
+ # This is a normal array or a list of variable names
+ # shellcheck disable=SC2006
+ eval "`$_parset_PARALLEL_PRG -k --_parset var,"$_parset_NAME" "$@"`"
+ # The eval returns the function!
+ fi
+}