6

Like in other programming language, is there a way of running linux shell command in Pharo smalltalk or a simple script ? I would like to have my Pharo image running a script that should be able to automate a tasks and return it to some value. I looked at almost all the documentation around and I couldn't find anything related. Maybe It does not allow such functionality.

6
  • Possible duplicate of Invoking shell commands from Squeak or Pharo
    – eMBee
    Commented Jul 16, 2018 at 17:04
  • @eMBee How is that a duplicate?
    – ludo
    Commented Jul 17, 2018 at 6:54
  • Do you want to call a command line tool from within Pharo or write a command line tool with Pharo? The first would be a duplicate of Invoking shell commands from Squeak or Pharo. Installing OSProcess from the Pharo Project Catalog would be a solution for this.
    – MartinW
    Commented Jul 17, 2018 at 7:20
  • you are asking to run a shell command and get some return value. the other question asks about invoking a shell command and capturing the output. those are pretty much the same thing. the answer to your question could just as well be an answer to the other question. the only problem with the other question is that none of the answers explain how to capture the output. i am suggesting that your question might be a duplicate. i am not declaring that it is. if your question is any different then please feel free to elaborate.
    – eMBee
    Commented Jul 17, 2018 at 13:26
  • as it is, i would suggest the answers of the two questions be merged, and one question be marked duplicate of the other.
    – eMBee
    Commented Jul 17, 2018 at 13:26

2 Answers 2

11

Pharo does allow the OS interaction. The best way, in my eyes, is to use OSProcess (as MartinW already suggested).

Those that think it is a duplicate are missing this part:

... running a script that should be able to automate a tasks and return it to some value...

There is nothing about return value in the invoking shell commands from squeak or pharo

To get a return value you would do it the following way:

command := OSProcess waitForCommand: 'ls -la'.
command exitStatus.

If you print out the above code you will get most probably a 0 as success.

If you do an obvious error:

command := OSProcess waitForCommand: 'ls -la /dir-does-not-exists'.
command exitStatus.

You will get ~= 0 value in my case 512.

Edit adding more details to cover more ground

I agree with eMBee that a statement

return it to some value

is rather vague. I'm adding information about I/Os.

As you may know there are three basic IO: stdin, stdout, and stderr. These you need to interact with shell. I'll add these examples first then I'll get back to your description.

Each of them is represented by instance of AttachableFileStream in Pharo. For the above command you will get initialStdIn (stdin), initialStdOut (stdout), initialStdError (stderr).

To write into the terminal from Pharo:

  1. stdout and stderr (you stream string into terminal)

    | process |
    
    process := OSProcess thisOSProcess.
    process stdOut nextPutAll: 'stdout: All your base belong to us'; nextPut: Character lf.
    process stdErr nextPutAll: 'stderr: All your base belong to us'; nextPut: Character lf.
    

Check your shell you should see the output there.

  1. stdin - to get what you typed

    | userInput handle fetchUserInput |
    
    userInput := OSProcess thisOSProcess stdIn.
    handle := userInput ioHandle.
    "You need this in order to use terminal -> add stdion"
    OSProcess accessor setNonBlocking: handle.
    fetchUserInput := OS2Process thisOSProcess stdIn next.
    "Set blocking back to the handle"
    OSProcess accessor setBlocking: handle.
    "Gets you one input character"
    fetchUserInput inspect.
    

If you want to grab an output from the command into Pharo a resonable way is to use PipeableOSProcess which, as apparent from his name, can be used in conjunction with pipes.

Simple example:

| commandOutput |

commandOutput := (PipeableOSProcess command: 'ls -la') output.
commandOutput inspect.

More complex example:

| commandOutput |

commandOutput := ((PipeableOSProcess command: 'ps -ef') | 'grep pharo') outputAndError.
commandOutput inspect.

I like the use of outputAndError because of typos. If you have an incorrect command you will get the error message:

| commandOutput |

commandOutput := ((PipeableOSProcess command: 'ps -ef') | 'grep pharo' | 'cot') outputAndError.
commandOutput  inspect.

In this case '/bin/sh: cot: command not found'

That is about it.

Update 29-3-2021 The OSProcess works up to Pharo 7. It was not upgraded to work with the changes at Pharo 8 or newer.

4
  • "There is nothing about return value in the invoking shell commands from squeak or pharo": uhm, the other question does mention "capture the output of commands", so yes, that question does ask for the return value. nevertheless your answer is better than the others.
    – eMBee
    Commented Jul 17, 2018 at 13:18
  • btw: neither question is clear on exactly which value they want. whether the exitstatus or the output on stdout or stderr. it would be nice if you could add both to your answer.
    – eMBee
    Commented Jul 17, 2018 at 13:30
  • @eMBee Well you are right. I have added both ways.
    – tukan
    Commented Jul 18, 2018 at 9:34
  • @eMBee hehe, glad you like it.
    – tukan
    Commented Jul 19, 2018 at 6:26
0

If you are using a newer Pharo you do not need dependencies. You can run:

LibC uniqueInstance resultOfCommand: 'ls -la'.

Not the answer you're looking for? Browse other questions tagged or ask your own question.