Return value

Q&A's, tips, howto's
Locked
Dave
Posts: 6
Joined: Sun Jun 01, 2003 5:54 pm

Return value

Post by Dave »

How does one get the return value for exec?

(set 'x (exec "command")) seems to return a nil x, regardless if the command is successful or not.

HPW
Posts: 1390
Joined: Thu Sep 26, 2002 9:15 am
Location: Germany
Contact:

Post by HPW »

Works for me in windows.
But I have to kill the DOS-window.

Code: Select all

> (set 'x (exec "command"))
("Microsoft(R) Windows DOS" "(C)Copyright Microsoft Corp 1990-2001." 
 "" "C:\\PROGRA~1\\NEWLISP>") 
This works:

Code: Select all

> (set 'x (exec "dir un*.exe"))
(" Datentr?ger in Laufwerk C: ist Festplatte" " Volumeseriennummer: 4875-9A91" 
 "" " Verzeichnis von C:\\Programme\\newlisp" "" "26.09.2005  19:38            35.923 uninstall.exe" 
 "               1 Datei(en)         35.923 Bytes" "               0 Verzeichnis(se), 91.052.036.096 Bytes frei") 
Added later:
The above test was with newLISP-TK!
In native newLISP-shell the first hang up and the second work.
Last edited by HPW on Sat Oct 08, 2005 2:43 pm, edited 1 time in total.
Hans-Peter

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Post by Lutz »

I don't have access to a Windows machine at the moment, but I think you can seperate commands with a semicolon in a DOS window and could put an 'exit' as a second statement:

(exec "dir *.exe; exit")

if exec returns 'nil' then it did not find the command shell try this instead:

(exec "cmd /c dir *.exe")

this would be 'cmd' for the NT cmd command shell and 'command' for older versions of Windows

Lutz

Dave
Posts: 6
Joined: Sun Jun 01, 2003 5:54 pm

Post by Dave »

I'm using newLISP as a scripting language under FreeBSD.

I am unclear about the term "return value", whether it is the data returned from the system process (say, a directory), or if it is the exit status of the process (success/fail). The reference says "The return value true is the process was successfully launched, else nil" (I think is s/b "if" btw). I am looking for the status of the process in this instance. I tried to query "$?", with the same results; nil on both pass and fail.

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Post by Lutz »

There are two forms of the syntax, with and without the second argument:

(1) 'exec' returns 'nil' if it could not launch the command given, else it returns a list of strings, each string beeing one of the output lines of std-out of the process launched.

(2) with the second argument given (stdin to the process), the return value is 'true' on success and 'nil' if the process could not be launched.

Lutz

Dave
Posts: 6
Joined: Sun Jun 01, 2003 5:54 pm

Post by Dave »

(set 'x (exec "ls /a_directory")) --- x will be the contents of the directory.
(set 'x (exec "ls /empty_directory")) --- x will be empty.

But this is where I have trouble understanding:

(set 'x (exec "ls /not_a_directory")) --- x will be empty NOT null, and the OS will output an error message.
(set 'x (exec "not_an_instruction")) --- x will be empty NOT null, and the OS will output an error message.

I am trying to test for failed calls to the system, and deal with them before they are sent to the output. Should I be using some form of catch/throw? How is it used in this way?

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Post by Lutz »

'exec' launches a shell process and returns whatever was standard-out via a pipe mechanism. There is no way to check stdout from the launched process before it gets returned. 'exec' fails if the command in exec couldn't be launched returning a 'nil'.

If you want a more direct control over OS system calls you could import system calls from the libraries of your OS. I.e.:

(import "libc.so" "kill")

could be used to import the kill system call and then you could do a:

(kill pid 9)

To send SIGKILL to a process ID and the function would return 0 for sucess -1 for error etc.

The purpose of 'exec' is to execute OS utilities/programs in a shell like fashion and capture stdout. But there is a way to capture std error using the following method:

Code: Select all

> (exec "ls *.abc 2>&1")
("ls: *.abc: No such file or directory") 
> 
The 2>&1 spec tell ls to redirect error output to stdout. This way it gets captured in the list returned by exec.

Lutz

Dave
Posts: 6
Joined: Sun Jun 01, 2003 5:54 pm

Post by Dave »

Very informative answer, Lutz! It shows me some things I will have to study.

Thanks. I'm a fan!

statik
Posts: 58
Joined: Thu Apr 14, 2005 1:12 am

Post by statik »

The 2>&1 is a format for stderr redirection that is only valid with the bourne-again shell. Keep that in mind when developing; all shells use different syntax when using stdio/out/err redirection.
-statik

Dmi
Posts: 408
Joined: Sat Jun 04, 2005 4:16 pm
Location: Russia
Contact:

Post by Dmi »

Just checked 2>&1 on Tru64 with ksh and pure sh - it works like bash.
Even command.com (AFAI remember) works this way, despite in it it's only "idiom", I think.
WBR, Dmi

Dmi
Posts: 408
Joined: Sat Jun 04, 2005 4:16 pm
Location: Russia
Contact:

Post by Dmi »

Btw, there is a nice way in unix shell:

Code: Select all

$ mknod pipe p
$ ls pipe
prw-r--r--  1 dmi users 0 Oct 15 00:44 pipe
$ cat pipe >error&
[1] 22755
$ ls nonexistent 2>pipe
$ cat error
ls: nonexistent: No such file or directory
...but there is some special things about locking and end of file on the named pipe's ends
WBR, Dmi

nigelbrown
Posts: 429
Joined: Tue Nov 11, 2003 2:11 am
Location: Brisbane, Australia

Post by nigelbrown »

Lutz wrote: ...
If you want a more direct control over OS system calls you could import system calls from the libraries of your OS. I.e.:

(import "libc.so" "kill")
...
Lutz
Trying on Suse 10 I get (using newlisp compiled on system from source):
nigel@linux:~/newlisp-8.7.1> ./newlisp
newLISP v.8.7.1 on linux, execute 'newlisp -h' for more info.

> (import "libc.so" "kill")
/usr/lib/libc.so: invalid ELF header
problem loading library in function import : "libc.so"

>

Looking at libc.so shows:
linux:/home/nigel # ls -l /usr/lib/libc.so
-rw-r--r-- 1 root root 204 2005-09-10 03:20 /usr/lib/libc.so

I really want to call getuid (to find if newlisp is running as root).
Any tips on calling from libc ?

Nigel

newdep
Posts: 2038
Joined: Mon Feb 23, 2004 7:40 pm
Location: Netherlands

Post by newdep »

What happens when you provide the whole path?
>(import "/lib/libc.so.6" "fopen")

what does "ldd" give on libc.so ?
(Looks like the libc you revering to is not a shared lib...)
-- (define? (Cornflakes))

nigelbrown
Posts: 429
Joined: Tue Nov 11, 2003 2:11 am
Location: Brisbane, Australia

Post by nigelbrown »

Thanks for pointing out the correct path - works as required viz:

nigel@linux:~/newlisp-8.7.1> ./newlisp
newLISP v.8.7.1 on linux, execute 'newlisp -h' for more info.

> (import "/lib/libc.so.6" "fopen")
fopen <401CF720>
> (import "/lib/libc.so.6" "getuid")
getuid <402075E0>
> (getuid)
1000
> (exit)
nigel@linux:~/newlisp-8.7.1> su
Password:
linux:/home/nigel/newlisp-8.7.1 # ./newlisp
newLISP v.8.7.1 on linux, execute 'newlisp -h' for more info.

> (import "/lib/libc.so.6" "getuid")
getuid <402075E0>
> (getuid)
0
>

as you expected:
linux:/home/nigel/newlisp-8.7.1 # ldd /usr/lib/libc.so
ldd: warning: you do not have execution permission for `/usr/lib/libc.so'
not a dynamic executable
linux:/home/nigel/newlisp-8.7.1 # ldd /lib/libc.so.6
/lib/ld-linux.so.2 (0x40000000)
linux-gate.so.1 => (0xffffe000)

Regards
Nigel

Locked