Take the 2-minute tour ×

My app uses NSTask to execute shell scripts, one of those scripts launches an X11 app (specifically meld).

I would have expected this to work:

source ~/.profile                      # setup $PATH/etc
meld .

But it fails with:

Traceback (most recent call last):
  File "/usr/local/bin/meld", line 132, in <module>
AttributeError: 'NoneType' object has no attribute 'append_search_path'

As a proof of concept I changed the script to this, which works perfectly:


exec 'osascript -e \'tell app "Terminal" to do script "meld ' + Dir.pwd + '" in front window\''

Does anyone what is causing the problem? Here is my code for executing the shell script:

NSTask *task = [[NSTask alloc] init];
task.launchPath = self.scriptURL.path;
task.standardOutput = [NSPipe pipe];
task.currentDirectoryPath = workingDirectoryURL.path;

[task launch];
share|improve this question
add comment

3 Answers

up vote 2 down vote accepted

X11 apps learn the display server's address using the DISPLAY environment variable.

On OS X, the DISPLAY value is randomized for security reasons, so you can't hard-code it, as you noticed. Instead, there is a launchd agent that tells launchd to set DISPLAY when it starts a process.

Somewhere between launchd and meld, the value of DISPLAY is being dropped or overwritten. Your job is to find out where.

  1. Make sure the launchd agent is running. Run launchctl list and look for org.macosforge.xquartz.startx. Since meld is working from Terminal.app this part is probably correct.
  2. Make sure DISPLAY is set in your app. It should be listed in [NSProcessInfo processInfo].environment.
  3. Make sure DISPLAY is set in the NSTask you launch. Try running /usr/bin/env with an NSTask, and make sure DISPLAY appears in its output.
  4. Make sure DISPLAY is set inside the script you run. Try echo $DISPLAY before and after sourcing ~/.profile. (Sometimes the .profile itself overwrites DISPLAY to an incorrect value because that's sometimes the right thing to do on other operating systems.)

EDIT: this is the code I used to copy DISPLAY from my GUI app to the shell script:

NSTask *task = ...
task.environment = [NSProcessInfo processInfo].environment;
share|improve this answer
Item 2 in your list was the issue. I had to manually copy ENV from my GUI app to the shell script it was launching. Perhaps this would normally be done automatically but I was setting other environment variables, which might have stomped all over it. –  Abhi Beckert Apr 2 '13 at 7:26
add comment

Change your script to spew the environment variables and compare "working" to "not-working".

There are subtle differences between how shells are initialized across the different execution models. Almost assuredly, the environment is the source of your issues.

share|improve this answer
Thanks! I needed this: export DISPLAY=/tmp/launch-e6qXkg/org.macosforge.xquartz:0. It looks like the value changes on every reboot however, so I'll need to look into it further... –  Abhi Beckert Mar 27 '13 at 4:11
There ought to be something in the X11 environment that spews the DISPLAY variable once launched, given that it is dynamically set. (Been too long since I've mucked w/X). –  bbum Mar 27 '13 at 5:21
add comment

Take a look at man launchctl

launchctl submit ... -p /usr/local/bin/meld -- .

to have launchd launch the job; that will set certain environment variables for you that are part of the per-user session.

share|improve this answer
add comment

Your Answer


