Python long listing directory (ls -l), ls * - python

I'm trying to to a ls -l from python, to check for the last modification date of a file.
os.listdir doesn't show the long list format.
subprocess.call shows the format, but actually prints it, and returns 0. I want to be able to put it in a variable. Any ideas ?
Also, I tried
subprocess.call("ls","*.py")
which answers
ls: cannot access *.py: No such file or directory
it works with shell=True, but if someone could explain why it doesn't work without it, I'll appreciate. If you know how to make it work, even better.

It doesn't work without shell=True because the * is a shell expansion character - going from *.py to a list of files ending in .py is a function performed by the shell itself, not ls or python.
If you want to get the output of a command invoked via subprocess, you should use subprocess.check_output() or subprocess.Popen.
ls_output = subprocess.check_output(['ls', '-l'])

With nice formatting:
import subprocess
print(subprocess.check_output(['ls', '-lh']).decode('utf-8'))

Related

how to use subprocess.check_output() in Python to list any file name as "abc*"

I have couple of file with same name, and I wanted to get the latest file
[root#xxx tmp]# ls -t1 abclog*
abclog.1957
abclog.1830
abclog.1799
abclog.1742
I can accomplish that by executing below command.
[root#xxx tmp]# ls -t1 abclog*| head -n 1
abclog.1957
But when I am trying to execute the same in python , getting error :
subprocess.check_output("ls -t1 abclog* | head -n 1",shell=True)
ls: cannot access abclog*: No such file or directory
''
Seems it does not able to recognize '*' as a special parameter. How can I achieve the same ?
As others noted, your code should work. It doesn't work probably because the current directory isn't the one you suppose it is, so abc* is not expanded by the shell (even if shell=True is set), and passed as-is to ls, resulting in a "no such file" error.
You have to pass the absolute path or use cwd= parameter when calling check_output. Another nice pythonic alternative would be to avoid subprocess, and return the most recently modified file using only python code:
most_recent = max(glob.glob(os.path.join("path/to/file","abclog*"),key=os.path.getmtime)
(using max with os.path.getmtime as key and glob.glob to filter the files)
Make sure you execute this in the directory where the files exist. If you just fire up Idle to run this code, you will not be in that directory.

How to pass list of files into Python subprocess

I am trying to execute a system executable on UNIX with python. I have used op.system() to do this, but really need to use subprocess.call() instead. My op.System call is below:
os.system('gmsh default.msh_timestep%06d* animation_options.geo' %(timestep));
and works fine. It calls the program gmsh and gmsh reads a series of files specified in default.msh_timestep%06d*. I then try to do the equivalent thing with subprocess, but I get errors saying that the files are not there. Below is the subprocesses call:
call(["gmsh", "default.msh_timestep%06d*" %(timestep), "animation_options.geo"],shell=True);
Does anyone know what could be going on here? I'm admittedly a Python noob, so this might be a silly question.
Globbing is done by the shell for you. In Python, you need to do it yourself. You can use glob.glob to get file list that match the pattern:
import glob
call(["gmsh"] + glob.glob("default.msh_timestep%06d*" % (timestep,)) +
["animation_options.geo"])
If you want to use shell=True, pass a string isntead of a list of strings:
call("gmsh default.msh_timestep%06d* animation_options.geo" % (timestep,), shell=True)

Applying a perl script to every file in a directory and obtain output using Python

I am trying to make a python script that will open a directory, apply a perl script to every file in that directory and get its out put in either multiple text files or just one.
I currently have:
import shlex, subprocess
arg_str = "perl tilt.pl *.pdb > final.txt"
arg = shlex.split(arg_str)
import os
framespdb = os.listdir("prac_frames")
for frames in framespdb:
subprocess.Popen(arg, stdout=True)
I keep getting *.pdb not found. I am very new to all of this so any help trying to complete this script would help.
*.pdb not found means exactly that - there won't be a *.pdb in whatever directory you're running the script... and as I read the code - I don't see anything to imply it's within 'frames' when it runs the perl script.
you probably need os.chdir(path) before the Popen.
How do I "cd" in Python?
...using a python script to run somewhat dubious syscalls to perl may offend some people but everyone's done it.. aside from that I'd point out:
always specify full paths (this becomes a problem if you will later say, want to run your job automatically from cron or an environment that doesn't have your PATH).
i.e. 'which perl' - put that full path in.
./.pdb would be better but not as good as the fullpath/.pdb (which you could use instead of the os.chdir option).
subprocess.Popen(arg, stdout=True)
does not expand filename wildcards. To handle your *.pdb, use shell=True.

Python: system command

I spend a few hours writing a little script.
Basically what it does is create a new text file and fills it up with whatever.
I zip the text file --using zipfile-- and here's where my problem lies.
I want to run the Windows system command:
copy /b "imgFile.jpg" + "zipFile.zip" newImage.jpg
To merge the image "imgFile.jpg" and the zip "zipFile.zip".
So:
os.system("copy /b \"imgFile.jpg\" + \"zipFile.zip\" newImage.jpg")
When I run my script, it all seems to go fine.
But when it's done and I try to extract the 'newImage.jpg' file, it gives me:
The archive is either in unknown format or damaged
This ONLY happens when I run the system command within the script.
It works fine when I use the shell. It even works if I use a separate script.
I've double checked my zip file. Everything is in good shape.
Is there something I'm doing wrong? Something I'm not seeing?
Have you tried using shutil?
import shutil
shutil.copy(src, dst)
There may be a problem with the way Python is passing the arguments to the shell command. Try using subprocess.call. This method takes arguments as an array and passes them that way to the command:
import subprocess
subprocess.call(["copy", "/b", '"imgFile.jpg" + "zipFile.zip"', "newImage.jpg"])

When I write a python script to run Devenv with configure "Debug|Win32" it does nothing

Update: When I use the subprocess.call instead of subprocess.Popen, the problem is solved - does anybody know what's the cause? And there came another problem: I can't seem to find a way to control the output... Is there a way to redirect the output from subprocess.call to a string or something like that? Thanks!
I'm trying to use Devenv to build projects, and it runs just fine when i type it in command prompt like devenv A.sln /build "Debug|Win32" - but when I use a python to run it using Popen(cmd,shell=true) where cmd is the same line as above, it shows nothing. If I remove the |, change it to "Debug" only, it works....
Does anybody know why this happens? I've tried putting a \ before |, but still nothing happened..
This is the code I am using:
from subprocess import Popen, PIPE
cmd = ' "C:\\Program Files\\Microsoft Visual Studio 8\\Common7\\IDE\\devenv" solution.sln /build "Debug|Win32" '
sys.stdout.flush()
p = Popen(cmd,shell=True,stdout=PIPE,stderr=PIPE)
lines = []
for line in p.stdout.readlines():
lines.append(line)
out = string.join(lines)
print out
if out.strip():
print out.strip('\n')
sys.stdout.flush()
...which doesn't work, however, if I swap Debug|Win32 with Debug, it works perfectly..
Thanks for every comment here
There is a difference between devenv.exe and devenv.com, both of which are executable and live in the same directory (sigh). The command lines used in the question and some answers don't say which they want so I'm not sure which will get used.
If you want to call from the command line then you need to ensure you use devenv.com, otherwise you're likely to get a GUI popping up. I think this might be the cause of some (but not all) of the confusion.
See section 17.1.5.1. in the python documentation.
On Windows, Python automatically adds the double quotes around the project configuration argument i.e Debug|win32 is passed as "Debug|win32" to devenv. You DON'T need to add the double quotes and you DON'T need to pass shell=True to Popen.
Use ProcMon to view the argument string passed to devenv.
When shell = False is used, it will treat the string as a single command, so you need to pass the command/arugments as a list.. Something like:
from subprocess import Popen, PIPE
cmd = [
r"C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\devenv", # in raw r"blah" string, you don't need to escape backslashes
"solution.sln",
"/build",
"Debug|Win32"
]
p = Popen(cmd, stdout=PIPE, stderr=PIPE)
out = p.stdout.read() # reads full output into string, including line breaks
print out
try double quoting like: 'devenv A.sln /build "Debug|Win32"'
Looks like Windows' shell is taking that | as a pipe (despite the quotes and escapes). Have you tried shell=False instead?

Categories