11

How do I export a function from zsh, so that I can use it in gnu parallel?

example:

function my_func(){ echo $1;}
export -f my_func
parallel "my_func {}" :::  1 2

in bash will output

1
2

whereas in zsh it will output error messages

/bin/bash: my_func: command not found
/bin/bash: my_func: command not found
Bilal Syed Hussain
  • 8,664
  • 11
  • 38
  • 44
  • Why do your error messages begin with `/bin/bash`? Does that mean that GNU `parallel` is running `/bin/bash` despite the fact that you have `SHELL=/bin/zsh` set in the environment? Or do you have `SHELL=/bin/bash` set? – Jonathan Leffler Mar 29 '14 at 23:57
  • @JonathanLeffler I think `parallel`, being another GNU program, tries to interpret a missing command as a function, in which case it spawns a `bash` shell to attempt to call it. – chepner Mar 30 '14 at 00:42
  • GNU Parallel uses $SHELL. /bin/sh if $SHELL is unset. – Ole Tange Mar 30 '14 at 02:07

4 Answers4

9

zsh does not have a concept of exporting functions. export -f somefunc will print the function definition, it will not export a function.

Instead, you can rely on the fact that bash functions are exported as regular variables starting with ():

export my_func='() { echo "$1"; }'
parallel --gnu "my_func {}" ::: 1 2 
that other guy
  • 116,971
  • 11
  • 170
  • 194
  • 1
    That is true but can you *rely* on it? It's certainly not documented. – rici Mar 30 '14 at 01:22
  • 4
    As the author of GNU Parallel I can say that GNU Parallel relies on that when transferring functions to remote machines. I was quite baffled, when I found out that you cannot have a normal variable that starts with '() {' This had quite unexpected results: i='() {' bash -c 'echo $i' – Ole Tange Mar 30 '14 at 02:01
  • This even works with mutiline functions! `function my_func(){ echo $1;}` `export my_func="`whence -f my_func | sed -e 's/my_func //' `"` `parallel "my_func {}" ::: 1 2` – Bilal Syed Hussain Mar 30 '14 at 02:19
  • 1
    @OleTange The zsh workaround specified in the [man page](http://www.gnu.org/software/parallel/man.html) doesn't seem to work. I'm running zsh 5.0.5. Any ideas? – nachocab Nov 02 '14 at 20:36
  • 2
    @nachocab Yeah: It seems the workaround was killed by the Shellshock fix in Bash. Currently I have no solution to that. If you find one, please let me know. – Ole Tange Nov 02 '14 at 20:43
  • @WaelJ If you upgrade Bash to post-shellshock, you will also need to upgrade GNU Parallel to version Shellshock or later. – Ole Tange Nov 02 '14 at 20:44
  • @OleTange is this solution still valid? – shadowtalker Jun 28 '16 at 17:55
  • 2
    @ssdecontrol No. Use env_parallel to import zsh functions, variables, and arrays. – Ole Tange Jun 28 '16 at 17:59
6

Based on that other guy's answer. You can write a function that export a zsh function that already defined to bash

function exportf (){
    export $(echo $1)="`whence -f $1 | sed -e "s/$1 //" `"
}

Usage

function my_func(){
    echo $1;
    echo "hello";
}

exportf my_func
parallel "my_func {}" :::  1 2
Bilal Syed Hussain
  • 8,664
  • 11
  • 38
  • 44
5

A lot has changed since 2014.

Today you simply do:

# Activate env_parallel function (can be done in .zshenv)
. `which env_parallel.zsh`

function my_func(){ echo $1;}
env_parallel "my_func {}" :::  1 2

If your environment is big:

# Activate env_parallel function (can be done in .zshenv)
. `which env_parallel.zsh`

# Record which environment to ignore
env_parallel --session

function my_func(){ echo $1;}
env_parallel "my_func {}" :::  1 2
Ole Tange
  • 31,768
  • 5
  • 86
  • 104
  • I got `_bodies_of_ALIASES:alias:3: bad option: -o` when executing the 3rd command 1st code block. zsh: 5.8, parallel: 20210822. – Teddy C Sep 11 '21 at 14:22
  • @TeddyC File a bug report. I cannot reproduce it, so it depends on your environment. https://www.gnu.org/software/parallel/man.html#bug-dependent-on-environment – Ole Tange Sep 11 '21 at 18:34
  • Thanks for the reply! Tried it again in a clean zsh environment on my machine and it works. :) Perhaps the `env_parallel.zsh` script has conflict with some of my defined aliases / functions, but I'm not sure which ones. – Teddy C Sep 12 '21 at 04:29
3

This approach allows you to define a function in zsh (without worrying about adding a quote level). Also it does not require adding additional software.

Make a function. Here's one:

function bar {
    echo bar
    echo $1
}

And spin it up:

seq 10 | xargs -I{} -n1 -P1 zsh -c "$(whence -f bar); bar {}"

I'm using xargs at the minute but of course the same approach works for GNU Parallel, so thought I'd share it here.

William Entriken
  • 37,208
  • 23
  • 149
  • 195