newLISP Fan Club

Forum => newLISP in the real world => Topic started by: Dave on October 07, 2005, 07:55:17 PM

Title: Return value
Post by: Dave on October 07, 2005, 07:55:17 PM
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.
Title:
Post by: HPW on October 08, 2005, 12:39:24 AM
Works for me in windows.

But I have to kill the DOS-window.



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


This works:

> (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.
Title:
Post by: Lutz on October 08, 2005, 05:28:10 AM
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
Title:
Post by: Dave on October 08, 2005, 09:31:05 AM
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.
Title:
Post by: Lutz on October 08, 2005, 09:49:47 AM
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
Title:
Post by: Dave on October 09, 2005, 01:53:10 PM
(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?
Title:
Post by: Lutz on October 09, 2005, 02:57:04 PM
'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:



> (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
Title:
Post by: Dave on October 09, 2005, 03:45:25 PM
Very informative answer, Lutz! It shows me some things I will have to study.



Thanks. I'm a fan!
Title:
Post by: statik on October 14, 2005, 10:34:44 AM
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.
Title:
Post by: Dmi on October 14, 2005, 01:28:25 PM
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.
Title:
Post by: Dmi on October 14, 2005, 01:47:21 PM
Btw, there is a nice way in unix shell:
$ 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
Title:
Post by: nigelbrown on December 09, 2005, 06:18:11 AM
Quote from: "Lutz"
...

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
Title:
Post by: newdep on December 09, 2005, 06:28:11 AM
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...)
Title:
Post by: nigelbrown on December 09, 2005, 11:21:24 AM
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