In my current working directory I have the dir ROOT/ with some files inside.
I know I can exec cp -r ROOT/* /dst and I have no problems.
But if I open my Python console and I write this:
import subprocess
subprocess.call(['cp', '-r', 'ROOT/*', '/dst'])
It doesn't work!
I have this error: cp: cannot stat ROOT/*: No such file or directory
Can you help me?
Just came across this while trying to do something similar.
The * will not be expanded to filenames
Exactly. If you look at the man page of cp you can call it with any number of source arguments and you can easily change the order of the arguments with the -t switch.
import glob
import subprocess
subprocess.call(['cp', '-rt', '/dst'] + glob.glob('ROOT/*'))
Try
subprocess.call('cp -r ROOT/* /dst', shell=True)
Note the use of a single string rather than an array here.
Or build up your own implementation with listdir and copy
The * will not be expanded to filenames. This is a function of the shell. Here you actually want to copy a file named *. Use subprocess.call() with the parameter shell=True.
Provide the command as list instead of the string + list.
The following two commands are same:-
First Command:-
test=subprocess.Popen(['rm','aa','bb'])
Second command:-
list1=['rm','aa','bb']
test=subprocess.Popen(list1)
So to copy multiple files, one need to get the list of files using blob and then add 'cp' to the front of list and destination to the end of list and provide the list to subprocess.Popen().
Like:-
list1=blob.blob("*.py")
list1=['cp']+list1+['/home/rahul']
xx=subprocess.Popen(list1)
It will do the work.
Related
I am a newbie to python and linux. I want a solution for listing the files and folders based on the timestamp. I know this is already asked. But I cannot get an insight in what I am doing. I want the code to return the latest created file or folder. I have a script that identifies the type of content(file or folder). I need it to get the latest created content. The content identifier goes like this.
import os
dirlist=[]
dirlist2=[]
for filename in os.listdir('/var/www/html/secure_downloads'):
if (os.path.isdir(os.path.join('/var/www/html/secure_downloads',filename))):
dirlist.append(filename)
else:
dirlist2.append(filename)
print "For Folders",dirlist
print "For Files",dirlist2
Option 1: Use glob
I found this great article here: https://janakiev.com/blog/python-filesystem-analysis/
Option 2: Pipe the output of ls -l to python
The way I initially thought about solving this issue is doing the following...
You can list all the directories and their timestamps with ls -l.
Then you can pipe that output using subprocess like this:
import subprocess
proc=subprocess.Popen('echo "to stdout"', shell=True, stdout=subprocess.PIPE, )
output=proc.communicate()[0]
print(output)
To start i have little knowledge of python as i'm doing this assignment as a school project. I need to achieve the folowing:
create a script which i can start from Windows CMD and i need to add a parameter list to the first 3 files in a directory.
i start the script as follows:
c:\Python34\python.exe c:\Python34\directory.py c:\temp 3
content of the script:
##directory.py###
import os
import sys
dirs = os.listdir(sys.argv[1])
print (dirs)
The problem is i dont think the command line switch "3" is input in the script.
Any idea how i can achive this?
Your code doesn't actually reference the second command-line variable.
Are you trying to list the first n files in a directory? If so then try
import os
import sys
dir_arg=sys.argv[1]
num_arg=int(sys.argv[2]) #need to convert second argument to a number
dirs=os.listdir(dir_arg)
print dirs[:num_arg]
As other's have said sys.argv is simply a collection of command line arguments, so all you have to do is change your index in order to grab the appropriate values.
So, I want to create a simple script to create directories based upon the file names contained within a certain folder.
My method looks like this:
def make_new_folders(filenames, destination):
"""
Take a list of presets and create new directories using mkdir
"""
for filename in filenames:
path = '"%s/%s/"' % (destination, filename)
subprocess.call(["mkdir", path])
For some reason I can't get the command to work.
If I pass in a file named "Test Folder", i get an error such as:
mkdir: "/Users/soundteam/Desktop/PlayGround/Test Folder: No such file or directory
Printing the 'path' variable results in:
"/Users/soundteam/Desktop/PlayGround/Test Folder/"
Can anyone point me in the right direction?
First of all, you should use os.path.join() to glue your path parts together because it works cross-platform.
Furthermore, there are built-in commands like os.mkdir or os.makedirs (which is really cool because it's recursive) to create folders. Creating a subprocess is expensive and, in this case, not a good idea.
In your example you're passing double-quotes ("destination/filename") to subprocess, which you don't have to do. Terminals need double-quotes if you use whitespaces in file or folder names, subprocess takes care of that for you.
You don't need the double quotes. subprocess passes the parameters directly to the process, so you don't need to prepare them for parsing by a shell. You also don't need the trailing slash, and should use os.path.join to combine path components:
path = os.path.join(destination, filename)
EDIT: You should accept #Fabian's answer, which explains that you don't need subprocess at all (I knew that).
I have a directory structure like this:
--bin/
--lib/
--data/
So basically, the executable script is in bin and it calls the files in lib.. but lib has to communicate with the text files in data
Usually this use to work:
TO read a file in usually i use to do this
file_path = os.path.join(os.path.dirname(__file__))+ "/../" +"data/"+filename
f = open(file_path,"r")
But, in this instance, if i do:
print os.path.join(os.path.dirname(__file__))
returns nothing?
What am i doing wrong..
Thanks
I guess with nothing you mean an empty string? This could only be the case, if __file__ was an empty string in the first place. Did you accidentally overwrite __file__?
One other comment in addition to the others...the point of os.path.join is to avoid things like
mypath=dir + '/' + subdir + '/'+filename
This is done much more cleanly using
mypath=os.path.join(dir,subdir,filename) # can have as many arguments as you want!
Also, you can avoid explicit '..' and '.' in path names by using os.pardir and os.curdir. (e.g.)
file_path = os.path.join(os.path.dirname(__file__),os.pardir,'data',filename)
This should increase the portability of your code (and is a good habit to get into even if you don't plan on running this script anywhere else).
It depends on how you start your script, for example:
if /bin/script.py contains:
import os
print os.path.dirname(__file__) #no reason to use os.path.join()
then:
$> python /bin/script.py
/bin
$> cd /bin
$> python script.py
#nothing
$>
It'a a better idea to use the following:
file_path = os.path.abspath(__file__)
and then do whatever you want with that.
I want to make sure that I delete required files.
I have code something like
dir="/some/path/"
file = "somefile.txt"
cmd_rm= "rm -rf "+dir + file
os.system(cmd_rm)
The dir and file values are fetched from a database. How can I make sure I never end up running rm -rf /?
What things should I check before doing rm -rf?
Don't use the -r switch if you just want to remove a single file. Also, there could be spaces in the file name.
Better use the functions in Python's os module instead:
dirname = "/some/path/"
filename = "somefile.txt"
pathname = os.path.abspath(os.path.join(dirname, filename))
if pathname.startswith(dirname):
os.remove(pathname)
Normalizing the path with abspath and comparing it against the target directory avoids file names like "../../../etc/passwd" or similar.
You might consider using os.remove() instead since it's a great deal less dangerous than what you're attempting.
First, I suggest you to use the os.remove() and os.rmdir() functions for working with things like that. You will end up with more portable code and less headache for checking command return.
To check what you are effectively attempting to remove (you may not want to just check "/"), you can use some regular expressions on the generated path or just add a base path to all path returned from you database (depending what you are doing ...).
Use shutil.rmtree as Dave Kirby says. If you want to delete the just the file use:
dir = "/some/path/"
file = "somefile.txt"
cmd = os.path.join(dir, file)
shutil.rmtree(cmd)
If you want to delete the directory use:
dir = "/some/path/"
file = "somefile.txt"
shutil.rmtree(dir)
If the files are write protected make sure you have write permissions before you run this.
There is a module called shutil that provides shell-like file manipulation. If you want to delete a directory and all files and directories in it then use shutil.rmtree.
However it is implemented in python so if you are deleting a huge number of files then spawning rm may be faster, but will fail if the path has a space in it.
Assuming that your mentioning rm -rf is not just at random, but is exactly the command you need, why not just to call it? There is a lib allowing a greater integration with shell called sh.
from sh import rm
path_to_delete = '/some/path'
if os.path.exists(path_to_delete):
rm('-rf', path_to_delete)
PS Make sure you are not root and/or ask for user input to be extra cautious.
And, yes, smoke the man to avoid deleting a single file recursively ;)