I am writing a python code for a class which needs multiple lines of inputs.
For example I need the input to be in the format:
3 14
12 10
12 5
10 5
When entering this manually on the terminal, I do not know how to signal an end of input.
I have been working around it by entering the inputs in txt files and reading these.
On Linux, use Ctrl+D to type "end of file". On Windows, use Ctrl+Z.
Besides the control-d, in bash, you can also:
pythonscript <<EOF
3 14
12 10
12 5
10 5
EOF
On linux and unix you can find what the EOF char is using
stty -a
it will show something like
...
cchars: discard = ^O; dsusp = ^Y; eof = ^D; eol = <under>;
...
indicating the eof is ^D, which you can also change using stty.
Then, you can type ^D to signal EOF to a process that's reading its input from the terminal.
Related
I use subprocess.getstatus() to get output of bash command running inside python script, in my case top linux command:
output = subprocess.getoutput("top -bc -n 1 | grep some_process_name")
Unfortunately, output string of the function is limited to 80 chars. If the string is longer, I just get the first 80 chars.
Any other alternate way to get long outputs in shell commands, in full?
You could pipe the output to a text file, and then display the text file.
This question already has answers here:
Running Bash commands in Python
(11 answers)
Closed 2 years ago.
So I just recently started having interest and playing CTF's on OverTheWire website and I am still in the first challenge called the bandit Lvl5 if you'll consider looking at it. So it teaches the use of linux command line etc
So here on this challenge I am tasked that there are hidden files in home directory I have to find them and in one of those files I will find a password to go to the next level taking note the are over 20 hidden files that come up.
So I then thought no man yes I can go through this manually but it will take forever so I tried making a script that I thought would work to get the hidden files and open one by one. But it does not work as I wanted.
I wanted to append those hidden files into a list and then run a for loop that will open each one of them and then I will be able to see results and spot password
Code Below
import os
a = []
for i in os.system('find .inhere/'):
a.append(i)
for j in a:
print("\n\n cat j ")
So it my first time messing code of such manner trying to interact with the command line using python can you please help on how I can go about it or if my code can be fixed
os.system() only returns the exit status of the command (Not the STDOUT). You should use the subprocess module especially the subprocess.Popen. I have added several comments for my code for the better understanding.
Code:
import subprocess
import sys
def call_command(command):
"""
Call a command the STDOUT
:param command: The related command
:return: STDOUT as string
"""
result1 = subprocess.Popen(
command.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True
)
# Get the STDOUT and STDERR descriptors of the command.
std_out, std_err = result1.communicate()
return std_out
# Find files in test1 folder.
find_result = call_command("find test1/ -type f")
for one_find in find_result.split("\n"):
if one_find:
# The result of cat command will be in "cat_result" variable.
cat_result = call_command("cat {}".format(one_find))
print(cat_result)
# You can write the result directly to STDOUT with the following line.
# sys.stdout.write("\n".join(call_command("cat {}".format(one_find))))
Content of test1 folder:
>>> ll test1/
total 8
drwxrwxr-x 2 user grp 4096 Jul 8 14:18 ./
drwxrwxr-x 18 user grp 4096 Jul 8 14:33 ../
-rw-rw-r-- 1 user grp 29 Jul 8 14:18 test_file.txt
Content of test_file.txt:
>>> cat test1/test_file.txt
Contents of test_file.txt file
Output of the code:
>>> python3 test.py
Contents of test_file.txt file.
When using subprocess.Popen on a Windows interactive command-line program, and setting stdout = PIPE or stdout = somefileobject, the output will always be cut short, or truncated, as well as missing prompts and other text.
So my question is: How do I capture all of the output of the subprocess?
More Details below:
I am specifically trying to grab the output from steamcmd. Here are some code examples and outputs I've run through the Python environment in the terminal.
from subprocess import Popen
#This command opens steamcmd, logs in, and calls licenses_print. It dumps
#all licenses available to the user, and then quits the program.
cmd = (['path to steamcmd', 'arg1', 'arg2',...])
Popen(cmd)
In this I didn't set stdout to anything, so it dumps all output into the terminal and I can see everything. It's about 70 lines of text. The last few lines will be this, which is what I expect, and I get this from running steamcmd directly.
License packageID 166844:
- State : Active( flags 0 ) - Purchased : Sat Jun 2 12:43:06 2018 in "US", Wallet
- Apps : 620980, (1 in total)
- Depots : 620981, (1 in total)
But the moment I try to pass this into a file, like below
f = open('path to file', 'w+')
Popen(cmd, stdout = f).wait()
f.close()
The output dumped to the file gets cut short, and the last few lines look like this
License packageID 100123:
- State : Active( flags 512 ) - Purchased : Sat Jun 10 19:34:14 2017 in "US", Complimentary
- Apps : 459860, (1 in total)
- Depots : 4598
You can see it didn't make it to package 166844, and it stops in the middle of the line "- Depots : 459861, (1 in total)"
I have read that PIPE has a size limit and causes it to hang, but it never has hung for me, the output isn't nearly big enough, but I tried outputting straight to the file anyways and it hasn't worked. I've tried using check_output, getoutput, but I assume they use the same thing under the hood anyways.
So again, my question again is: How do I capture all the output from the subprocess?
Edit 1: I've tried reading it out line by line, but it still cuts at the same place. I've tried Powershell and Windows Command Prompt. I tried this same thing on Linux Mint, with the Linux build of Steamcmd. On Linux I was able to capture all the output from the subprocess and store it in the file. So this seems like it may not be a python issue, but a Windows, or Windows cli issue that is causing it to not capture all the output. I tell it to wait, send it to PIPE instead of a file, it will always cut it short. Somewhere the last of the output gets dropped before making to my file.
I am attempting to call netcat/nc from inside a loop, passing the lcv as the last octet in the command. I am seem to be running into an issue due to the fact that the variable is in the middle of the command. What I would like to do is:
for i in 1 to 50
print i
nc -nvv 192.168.1.i 21 -w 15 >> local_net.txt
So far I have tried:
os.system("nc -nvv 192.168.1.",i,"21 -w 15 >> local_net.txt")
and
subprocess.call(["nv","-nvv 192.168.1.",i,"21 -w 15 >> local_net.txt")
Is there an easier way to reference an LVC from within a command executing a system command?
The reason this doesn't work:
os.system("nc -nvv 192.168.1.",i,"21 -w 15 >> local_net.txt"
… is that os.system takes a single string, as a shell command. You're giving it three separate arguments. (Plus, even if this worked as you hoped, it would have to either put a space before the i or not put one after the i.) You could fix it by any of the usual ways of combining strings:
os.system("nc -nvv 192.168.1.{} 21 -w 15 >> local_net.txt".format(i))
os.system("nc -nvv 192.168.1." + str(i) + " 21 -w 15 >> local_net.txt".format(i))
However, your intuition to try subprocess.call instead was a good one. The reason this doesn't work:
subprocess.call(["nv","-nvv 192.168.1.",i,"21 -w 15 >> local_net.txt")
… is two-fold.
First, you're joining up multiple arguments. This is equivalent to the shell command:
nc '-nvv 192.168.1.' '1' '21 -w 15 >> local_net.txt'
When what you want is the equivalent to these:
nc -nvv 192.168.1.1 21 -w 15 >> local_net.txt
nc '-nvv' '192.168.1.1' '21' '-w' '15' >> 'local_net.txt'
You need to split up the arguments properly to get that.
Second, >> local_net.txt isn't part of the command itself at all; it's a shell redirection directive. You can't do that without the shell.
If you really want to use the shell, you can do it the same way as with system, but putting together a single single:
subprocess.call("nc -nvv 192.168.1.{} 21 -w 15 >> local_net.txt".format(i), shell=True)
But a better way to do this is to break the arguments up properly, and do the redirection Python-style instead of shell-style:
with open('local_net.txt', 'a+b') as f:
subprocess.call(["nc", "-nvv", "192.168.1.{}".format(i), "21", "-w", "15"],
stdout=f)
In the file mode, the a means to append to the end of the file; the + means to update the file if it exists, create it otherwise; the b means to open it in binary mode (so you don't translate newlines, if this is Windows—I'm assuming Python 2.x here).
Meanwhile, the Python version of for i in 1 to 50 is for i in range(1, 51):. (Note that 51 at the end, because Python ranges are half-open.) So, putting it all together:
for i in range(50):
with open('local_net.txt', 'a+b') as f:
subprocess.call(["nc", "-nvv", "192.168.1.{}".format(i), "21", "-w", "15"],
stdout=f)
It's worth noting that you can do this in most sh-like shells, including bash, without needing Python at all. And for something this simple, it may be easier:
for i in {1..50}; do
nc -nvv 192.168.1.${i} 21 -w 15 >> local_net.txt
done
my python script is the following code:
1 import subprocess
2
3 # initial 'output' to make
4 r0 = 21
5 # number of runs to make
6 rn = 10
7
8 rf = r0+rn
9
10 for i in range(r0, rf):
11 #output directory
12 opt_dir = 'output'+str(i)
13 #put it in this output directory
14 popt_dir = './output'+str(i)
15
16 subprocess.call(['mkdir', opt_dir])
17 subprocess.call(['./exp_fit', 'efit.inp'])
18 subprocess.call(['mv', 'at*', popt_dir])
the intention is this:
i have a program called "exp_fit" which takes an input file "efit.inp". one call to ./exp_fit efit.inp will create output files called 'at0_l0_l0', 'at0_l1_l-1', ... etc (total 475 files starting with 'at').
now, i have been generating data files by running 'exp_fit', then creating output directories and moving them into the output directories with the following bash commands:
(for example, with the 20th run of my code)
mkdir output20
mv at* ./output20
so i would think that my script should do the same thing. however, it only does the following:
(1) it correctly generates all output files (475 files starting with 'at')
(2) it correctly creates the desired directories (output21 - output30)
(3) it DOES NOT, however, correctly move all the output files starting with 'at' into the desired directories. why is this? shouldn't the call to line 18 correctly execute the command to move all my files starting with 'at' into the desired directory?
should i be writing this script with bash instead of python? what is wrong with this?
Don't issue subprocess calls for things you can do natively from Python. To move files/dirs around, just use os.rename.
To create a directory, use os.mkdir.
To execute an external program, using subprocess is the right tool.
The problem is that this subprocess command
subprocess.call(['mv', 'at*', './output20'])
is not the same as typing this at a prompt
$ mv at* ./output20
In the latter case, the bash glob expansion converts the single at* argument to a list of arguments of matching filenames for the mv command. So the kernel sees the second as
['mv', 'at0_l0_l0', 'at0_l1_l-1', './output20']
kev's answer tells Python to pass the command through the shell, so the escaping will occur.
But the better solution is to use the glob module and os.rename libraries and not call the subprocess. Creating subprocesses is expensive, and using shell=True could lead to security holes, so it's best to avoid that habit.
(Actually, I suggest making the output directory, switching into it, and then running the exp_fit program from within that directory. Then you won't have to move the output. Try that first.)
If shell=True, the executable argument specifies which shell to use.
On Unix, the default shell is /bin/sh.
subprocess.call(['mv', 'at*', popt_dir], shell=True)