posixtask(
SCRIPT
,
PROPERTY
,
VALUE
)

The posixtask( function executes a POSIX shell script in the background using NSTask.


Parameters

This function has three parameters:

script – specifies the shell script code to be run.

property – an optional script. See below for detailed descriptions of the different properties that can be specified. Properties can be specified in either upper or lower case, for example SCOPE or scope.

value – the value for the property specified by the previous parameter.


Description

This function executes a POSIX shell script in the background using NSTask. Unlike the posixscript function, this function doesn’t wait for the script to finish before continuing. The script will run in the background and the user can do other things while the script is running.

Although the script runs in the background, it’s not completely independent of Panorama. The script can send it’s output to Panorama variables, and you can specify Panorama code that will run automatically when the script is finished. The function returns a unique task identifier for the background task, which can be used with the waitfortask and stopposixtask statements. (You can also specify the task identifier, see below.)

WaitForTask

Although it’s not absolutely required, the posixtask( function is designed to be used with the waitfortask statement. This allows a procedure to launch a shell script, pause while the shell script runs, then resume after the shell script is finished. This example launches a shell script to list the contents of the Library folder, then displays the result.

waitfortask posixtask("cd ~/Library;ls -l")
displaydata _stdOut

Note that Panorama is not “locked up” while the shell script is running - you can perform other actions while the shell script is working. This is especially useful for long scripts that may take minutes to complete.

If you don’t need to pause while the script is running and then resume afterwards, you may find the posixtask statement simpler to use. This also runs a shell script in the background, but the Panorama code doesn’t pause and wait for the shell script to finish.

Shell Script

The first parameter used with this function must always be the shell script you want to run. This code consists of one or more POSIX shell commands, like this command that lists the contents of the current directory:

waitfortask posixtask("ls -l")

You can run two or more shell commands by joining them with a semicolon. This example lists the contents of the Library directory.

waitfortask posixtask("cd ~/Library;ls -l")

See Standard Output below to learn how to access the output from your shell commands.

There are hundreds of different shell commands available. Describing all of these commands is beyond the scope of this documentation, but there are many books available, as well as numerous web resources.

Note: Unlike the shellscript( function, no substitutions are performed on the script code, so you cannot embed Panorama variables and formulas into the code (of course you can use a formula to build the code any way you want).

Standard Output

UNIX shell scripts send all of there output to a portal called standard output. By default, the posixtask( function sends standard output to a local variable named _stdOut. You can access this local variable in the code you have set up to run after the script finishes. Here is a simple example that displays the contents of the Library directory in a dialog (using the displaydata statement).

waitfortask posixtask("cd ~/Library;ls -l")
displaydata _stdOut

If you wish, you can use the stdout option to customize the name of the variable used for standard output.

waitfortask posixtask("cd ~/Library;ls -l","stdout","libraryContents")
displaydata libraryContents

When you customize the name of the variable like this, Panorama will create the variable as a fileglobal variable instead of as a local variable. This allows you to display the variable in a form object. As the shell script generates output, Panorama will automatically update the form object as needed.

The posixtask( function appends the standard output to the specified variable. This means that if you run posixtask( more than once, the variable will contain the appended output of each run of the script. If you want only the most recent output you need to clear out the task before running the shell script, like this:

letfileglobal libraryContents = ""
waitfortask posixtask("cd ~/Library;ls -l","stdout","libraryContents")

If necessary, you can use the scope option to explicitly specify the type of variable that will be generated. The available scopes are local, database (fileglobal), window (windowglobal) and global. You can abbreviate these options with only the first letter (l, d, w or g). Here is an example that routes the output to a local variable named libraryContents.

waitfortask posixtask("cd ~/Library;ls -l",
    "scope","local",
    "stdout","libraryContents")
displaydata libraryContents

Note: If you plan to display the variable in a form, you should use the database option. Otherwise the variable will not update properly as output is generated.

Filtering Standard Output

This function normally takes the text generated by the shell script and sends it directly to the variable you have specified (or _StdOut if none was specified), without any modification. However, it is also possible to set up a formula to pre-filter the text, before it is sent to the variable. This can be especially useful if you are immediately displaying the text in a form.

The filter is set up with the linefilter option. It’s called linefilter because the text is filtered on a line by line basis. The option is a formula that takes the original text from the shell script (which is passed by the import() function) and transforms it into a modified value. This example converts the text to all upper case.

waitfortask posixtask("cd ~/Library;ls -l",
    "stdout","libraryContents",
    "linefilter,{upper(import()})

This example checks to see if the 4th word in each line contains admin. If it does, the line is pass through, if not, nothing is passed. This takes advantage of the fact that if nothing is passed, the line is not passed through to the variable at all, so this has the effect of only showing files that are owned by admin.

waitfortask posixtask("cd ~/Library;ls -l",
    "stdout","libraryContents",
    "linefilter,{?(nthword(onewhitespace(import()),4) contains "admin",import(),"")})

Standard Error

In addition to sending text to standard output, UNIX also has a standard error portal. By default, the posixtask( function sends standard error output to a local variable named _stdError. This works just like ths _stdOut variable, except that it will contain error information. You can use the stderror option to customize the name of the variable used for standard error.

waitfortask posixtask("cd ~/Library;ls -l",
    "scope","local",
    "stdout","libraryContents",
    "stderror","libraryError")
if libraryError<>""
   message libraryError
else
    displaydata libraryContents
endif

Note that the scope option controls both stdout and stderror - you cannot set the scope of these separately.

Script Task Identifier

Every script run in the background has a unique task identifier. The task identifier is normally assigned automatically, and looks someting like this:

871B0BDF-88DD-482E-B3C8-5237F30BE438-58013-00000172E0951E31

The posixtask( function returns this identifier, which you could later user to interact with the task, for example to stop it before it finishes. For example, a procedure could start a background spotlight search for Panorama databases like this:

letglobal spotLightTask = posixtask({mdfind -onlyin ~/ 'kMDItemFSName=*.pandb'})

Then another procedure (perhaps attached to a button named Stop Search) could use this code to stop the spotlight search before it finished.

stopposixtask spotLightTask

Instead of letting Panorama assign the task identifier automatically, you can assign an ID yourself by using the task or identifier option.

waitfortask posixtask({mdfind -onlyin ~/ 'kMDItemFSName=*.pandb'},"task","Spotlight Task")

If you specify a task ID it must be unique, you cannot run two tasks with the same name at the same time. If you do, the posixtask( function will fail with an error.

To get a list of all the currently running posix tasks, use the info(“posixtasks”) function. This will return a carriage return delimited list of all posix tasks that are currently running in the background.

Post Script Actions

You may want to run some additional Panorama code after the shell script is finished. To do that, use the "CODE" option. This example will delete all files within the SecretProject folder, then display a notification telling you that the files have been deleted.

posixtask "cd ~/Secret\ Project;rm -r *","code",{nsnotify "Secret Project Shredded!"}

Note: Be VERY careful with the rm shell command – it’s super dangerous.

By default, you cannot rely on Panorama being in a certain state when the code begins. For example, you should not rely on a particular window or database being active when the shell script finishes. In fact, the database that started running the script might not even be open by the time the script finishes running. So make sure you code defensively and check the state you perform any action that depends on that state.

Using WaitForTask with PosixTask

Earlier you learned how to use the code option to run Panorama code after the shell script finishes. There’s a second way to do this, using the waitfortask statement.

To use this technique you must set up a task identifier (as described in the previous section). Then you can follow the posixtask statemint with a waitfortask statement. The code will pause and wait for the shell script to finish in the background, then continue with the rest of the code. Since the shell script is running in the background, you can do other things in the meantime while this is happening, which can be very useful if the shell script takes minutes to finish.

posixtask "cd ~/Library;ls -l","task","Library Catalog"
waitfortask "Library Catalog"
displaydata _stdOut

You may think that the example above is the same as this example:

displaydata posixscript("cd ~/Library;ls -l")

The difference is that the first example allows other tasks to be performed while the shell script is running. In the second example everything stops until the script is finished - Panorama can’t do anything else until the script is finished.

Note: If you’re planning to use the waitfortask technique, you might want to switch over to the posixtask( function instead of the posixtask statement. This function is designed to make using waitfortask super simple, as shown here.

waitfortask posixtask("cd ~/Library;ls -l")
displaydata _stdOut

Advanced: It’s possible to combine the code option with the waitfortask technique. If you do, you must add the code resumeaftertask «taskid» at the end of your code:

posixtask "cd ~/Library;ls -l",
    "task","Library Catalog",
    "code",|||nsnotify "Catalog done" resumeaftertask «taskid»|||
waitfortask "Library Catalog"
displaydata _stdOut

The example above is rather silly, there’s really no reason why the nsnotify statement couldn’t be put after the waitfortask statement. We couldn’t think of a more realistic example of this technique, so probably you’ll never need to use this technique. But if you ever do, now you know how.


See Also


History

VersionStatusNotes
10.2NewNew in this version.