2

I have a command ./rancli -c - I enter in a shell that has this documentation:

Running the tool from the Linux shell allows additional options, depending on the options given to the command. The options are as follows:

-h Displays help about the command

-c Instead of taking typed commands interactively from a user the commands are read from the named file, i.e. in batch mode. When all commands are processed the CLI session ends automatically.

-c - As above but reads command from Linux stdin. This allows commands to be ‘piped’ to the program.

I wnat to convert this into python. If I use the second option everything works fine and it reads commands froma file and displays the results on screen. However I want to use the third option which writes to stdin. I would have thought this line would run a command ./rancli -c - commandHere but it does not. What I have to do is enter ./rancli -c - then I can write manually to stdin on the next line, such as here I use the command read hnb:

[root@switch]# ./rancli -c -
read hnb
RAN> read hnb
               HNBId                           Location      RegUEs   ActUEs
  000295-0000038828@ipaccess.com                    n/c
  000295-0000070688@ipaccess.com                    n/c

When i enter this in the shell I get the result printed out fine. However when i do it in my python I do not get the results printed back to me correctly. Here is what I tried:

    ran_opt_get_ap  = "read hnb\n"
    cmd_rancli = ["/jffs2/usbflash0/ran/rancli", "-c", "-"]
    proc = subprocess.Popen(cmd_rancli + [ran_opt_get_ap], stdout=subprocess.PIPE)    
    for line in iter(proc.stdout.readline, ''): 
        print line,
    proc.wait()

So when i pass in a command like that it obviously doesnt work like in the shell and is ignored. Now two issues here, How do I write the command to stdin here, seeing as I had to type the following command read hnb manually? After I run rancli -c - I want to then inject commands after, I have to type it in like so at the moment:

read hnb                                                                        
RAN> read hnb                   

The other issue is that my code did not print out the full results above but when I type in the next command I get the rest of the results and the first line of next result and so on with every command, getting the results after I type the next command:

get ap                                                                          
               HNBId                           Location      RegUEs   ActUEs    
  000295-0000038828@ipaccess.com                    n/c                         
  000295-0000070688@ipaccess.com                    n/c                         
RAN> get ap 

Update: latest code works

cmd_rancli = ["/jffs2/usbflash0/ran/rancli", "-c", "-"]
ran_opt_get_ap = "read hnb"
proc = subprocess.Popen(cmd_rancli, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
output = proc.communicate(ran_opt_get_ap)[0] 
print output
jfs
  • 399,953
  • 195
  • 994
  • 1,670
Paul
  • 5,756
  • 6
  • 48
  • 78
  • drop `[ran_opt_get_ap]` in `Popen()` call, add **`stdin=PIPE`** as in my answer. `bufsize=0` is unnecessary if you use `.communicate()` but it shouldn't hurt here either. – jfs Apr 11 '13 at 11:54
  • Thanks I did as you said with the pipe and it worked. Just had to remove the \r\n. – Paul Apr 11 '13 at 11:55
  • @J.F.Sebastian I put up the latest code, and it works, thanks so much. – Paul Apr 11 '13 at 11:57

1 Answers1

4

To write to subprocess' stdin, set it to PIPE:

from subprocess import Popen, PIPE

p = Popen(cmd_rancli, stdin=PIPE, stdout=PIPE)
output = p.communicate(ran_opt_get_ap)[0]

.communicate() writes ran_opt_get_ap to the subprocess' stdin, reads all output, and waits for the child process to finish.

The second issue is due to buffering (it only matters if you're not reading all output at once). To fix buffering:

Community
  • 1
  • 1
jfs
  • 399,953
  • 195
  • 994
  • 1,670
  • Thanks will try that, any difference in doing this for subprocess.PIPE or PIPE? stdin=subprocess.PIPE etc? – Paul Apr 11 '13 at 10:09
  • Tried your first suggestion got: for line in iter(proc.stdout.readline, ''): ValueError: I/O operation on closed file – Paul Apr 11 '13 at 10:13
  • Thanks for all the effort. If I put in sdtin=pipe then i never get any results and cant even exit, have to reset the device. If I use p.communicate(ran_opt_get_ap)[0] I never get an results either as I assume it's waiting for the process to finish? Either way I dont even get the the read code. – Paul Apr 11 '13 at 10:27
  • 1
    @Paul: Does rancli ignore EOF in its stdin? (try to type `Ctrl D` when you run it manually). If this is the case; how do you exit `rancli`, do you need to type a special command to do it? – jfs Apr 11 '13 at 10:35
  • if I run a rancli shell I can type exit or quit and it quits. However if I run it in this manner (with -c -) these commands dont seem to work so i always have to press control-d to exit. If I use ` p.communicate(ran_opt_get_ap)[0]` I can still control-d out of it but if I do stdin=pipe nothing quits out of it apart from a hardware reset. – Paul Apr 11 '13 at 10:38
  • I edited my question to show you how the quit commands dont work in this mode, even though it lists them. – Paul Apr 11 '13 at 10:40
  • also, when I press control-d the rest of the data is printed out that I wanted. – Paul Apr 11 '13 at 10:49
  • 1
    @Paul: `.communicate()` closes subprocess' stdin so `rancli` should receive EOF (and therefore it should exit). What happens if you run in bash: `echo read hnb | rancli -c - >output`? – jfs Apr 11 '13 at 10:52
  • If I type `echo read hnb | ./rancli -c -` then all my correct data is printed to the screen. Why is that, how come passing in the command into the line itself then doesnt work, should I use this method? I'm testing out communicate atm to see can i get it to exit out. – Paul Apr 11 '13 at 11:00
  • 1
    @Paul: run the *exact* command. Add `> output` at the end. Check: 1. `rancli` exits 2. `output` file contains expected output. – jfs Apr 11 '13 at 11:01
  • Forgot to say sorry, I ran that command but there was no output at all. Oh i forgot to check teh file one sec – Paul Apr 11 '13 at 11:03
  • in that case, `.communicate()`-based solution should work. It is equivalent to `echo read hnb | rancli -c - | cat > output`. Try different line-endings: `ran_opt_get_ap = b"read hnb\r\n"` (if there is a terminal-emulator behind the scenes; it might expect `\r\n` even on *nix). Try [`subprocess32`](https://pypi.python.org/pypi/subprocess32/) to make sure it is not a bug in your `subprocess` version. Post the full code (it should be 6 lines: 3 lines from my answer + 2 lines to define `cmd_rancli` and `ran_opt_get_ap` + 1 line: `print(repr(output))`) and whether you see the output. – jfs Apr 11 '13 at 11:30
  • I have done what you asked and put it in the question under updated code. – Paul Apr 11 '13 at 11:49
  • Actually I added in stdin=subprocess.PIPE and now the correct thing is printed! Thanks! It prints it and exits. – Paul Apr 11 '13 at 11:54