I have been trying to delete some symbolic links in my working directory, but I am facing some issues.
os.remove also removes the actual contents of the original folder of the link
os.shutil throws up an error in case of symbolic links.
Is there a way to remove a symbolic link using python commands without destroying the original content?
Thanks
os.unlink() works for me. It removes the symlink without removing the directory that it links to.
The accepted answer does not work on Windows with links created via mklink /D. If that is your problem the answer has been posted in this question: Delete Symlink to directory on Windows
The following code should work on both systems:
if(os.path.isdir(targetLink)):
os.rmdir(targetLink)
else:
os.unlink(targetLink)
Sorry,my Bad, I had made a stupid programming mistake : I was stupidly deleting the source instead of the links.
The correct answer is by #samfrances.
os.unlink does the trick.
In addition to this, here some other tips if you want to clear a directory using python:
Definitely not threadsafe, but you get the idea...
def rm(obj):
if os.path.exists(obj):
if os.path.isdir(obj):
if os.path.islink(obj):
os.unlink(obj)
else:
shutil.rmtree(obj)
else:
if os.path.islink(obj):
os.unlink(obj)
else:
os.remove(obj)
in Python 3.4 and above,
If link is a file, use unlink().
>>> from pathlib import Path
>>> p = Path('/some/file/')
>>> p.unlink()
If the path points to a directory, use Path.rmdir() instead.
>>> from pathlib import Path
>>> p = Path('/some/dir/')
>>> p.rmdir()
If the directory name contains a trailing slash, the linux rm command will follow the link and try to delete the directory. See Remove a symlink to a directory. The os.remove documentation says that it will give you an OSError if you try to remove a directory but maybe that doesn't always happen in the case of symlinks.
Related
This is relatively simple matter but for some reason I cannot find a way to get the full path of the windows temp directory via python or to find similar request already posted in stack overflow community.
I'm using tempfile.gettempdir() command but it seems there is no way to capture the full path and it returns the short version:
'C:\Users\SVETLO~1\AppData\Local\Temp'
This overall works but there is an important part of the script later on which doesn't and it requires the full temp dir path, which is:
C:\Users\SvetlozarDraganov\AppData\Local\Temp\
Does anyone knows how to get the full absolute path to windows-temp folder with python?
Thanks in advance.
Svet
Edit-1:
I'm testing the %fA suggestion from CMD but for some reason, it doesn't work. If I'm using %sA attribute it actually returns the short path version:
CMD: for %A in ("C:\Users\SvetlozarDraganov\AppData\Local\Temp") do #echo %~sA
OUTPUT: C:\Users\SVETLO~1\AppData\Local\Temp
The %fA attribute however doesn't return the full path:
CMD: for %A in ("C:\Users\SVETLO~1\AppData\Local\Temp") do #echo %~fA
OUTPUT: C:\Users\SVETLO~1\AppData\Local\Temp
Speaking of full absolute path, you already have it.
The "short version" is the 8.3 filename that exists before VFAT and the "full path" as you meant it is the "long filename" or LFN. They are interchangable so long as accessing the file in concern.
In Windows command prompt, you can use parameter expansions to convert from short to long and back. See the solution here for an example (replace %~sA in the answer with %~fA in your case). So you can make use of that and call the command with subprocess.run() to read the output.
I can't recall Python has a built-in function for doing this conversion. But Windows API does: You may want to see how this solution for converting LFN to short filename, which in your case, the function should be GetLongPathName() instead.
I found a out-of-the-box solution to my question in python os module:
https://docs.python.org/2/library/os.path.html#os.path.realpath
It returns the long-version path!
Thanks to everybody!
I'm trying to learn how to edit files, but I'm a bit of a python novice, and not all that bright, so when I get a FileNotFoundError I can't figure out how to fix it despite several searches on the interwebz.
import os
old = 'Users\My Name\Pictures\2013\182904_10201130467645938_341581100_n'
new = 'Users\My Name\Pictures\2013\Death_Valley_1'
os.rename(old, new)
'Users\My Name\Pictures\2013\182904_10201130467645938_341581100_n' is a relative path.
Unless you are running your code from the directory that contains the Users dir (which if you are using Windows would most probably be the root C: dir), Python isn't going to find that file.
You also have to make sure to include the file extension if it has any.
There are few ways to solve this, the easiest one will be to use the absolute paths in your code, ie 'C:\Users\My Name\Pictures\2013\182904_10201130467645938_341581100_n.jpg'.
You will also want to use r before the paths, so you want need to escape every \ character.
import os
old = r'C:\Users\My Name\Pictures\2013\182904_10201130467645938_341581100_n.jpg'
new = r'C:\Users\My Name\Pictures\2013\Death_Valley_1.jpg'
os.rename(old, new)
This of course assumes your drive letter is C.
I use python os.walk() to get files and dirs in some directories, but there're files whose names are too long(>300), os.walk() return nothing, use onerror I get '[Error 234] More data is available'. I tried to use yield, but also get nothing and shows 'Traceback: StopIteration'.
OS is windows, code is simple. I have tested with a directory, if there's long-name file, problem occur, while if rename the long-name files with short names, code can get correct result.
I can do nothing for these directories, such as rename or move the long-name files.
Please help me to solve the problem!
def t(a):
for root,dirs,files in os.walk(a):
print root,dirs,files
t('c:/test/1')
In Windows file names (including path) can not be greater than 255 characters, so the error you're seeing comes from Windows, not from Python - because somehow you managed to create such big file names, but now you can't read them. See this post for more details.
The only workaround I can think of is to map the the folder to the specific directory. This will make the path way shorter. e.g. z:\myfile.xlsx instead of c:\a\b\c\d\e\f\g\myfile.xlsx
The problem is the character limit for the path in windows when creating multiple directories using pythons os.makedirs()
I found this post when searching for my problem before posting this:
python win32 filename length workaround
Now the chosen answer suggests the prefix workaround but my question here is, is there a way to ensure functionality in Windows and UNIX?
The other approach I thought of was to create the folders one by one and then create the file so that you never exceed the path length, but I can't figure out the obvious bug in the code.
path = ['folder1/s1/s1/abc.txt',
'folder1/s1/s2/def.txt']
def makedirs(path):
explode = path.split('/')
for i in range(len(explode)-1):
os.mkdir(explode[i])
os.chdir(explode[i])
if i == len(explode) -2:
download_file(explode[i+1])
# something to go back here
os.chdir('../' * (len(explode)-3)) # ??
makedirs(path[0])
Now this works for only the first line because I can't figure out how to get back to the root or reset it. Without the 'reset' the folders are being under each other:
folder1/s1/s1/folder1/s1/s1/abc.txt (or something like that)
I could set the path from root to reset it but then we might run into the same issue of reaching the max length. Any help on how to get this working on both OS would be appreciated!
Please feel free to point out where I'm wrong.
you need to use unc path and unicode filenames, but not all python functions are aware of this, os.mkdir works while os.makedirs not
import os
path = u'\\\\?\\c:\\'
for i in xrange(1000):
path += u'subdir\\'
os.mkdir(path)
but it's better to give also the code to remove them, windows explorer is unable to delete
import os
path = u'\\\\?\\c:\\'
for i in xrange(1000, 0, -1):
try:
os.rmdir(path + (u'subdir\\' * i))
except:
pass
Per this stackoverflow answer: while chdir can go up one directory with os.chdir(".."), the platform-agnostic way is: os.chdir(os.pardir).
Either call this N times in a loop;
or try an unreadable one-liner like this (untested):
os.chdir(os.path.join(*([os.pardir] * NUM_TIMES)))
(Instead of path.split('/'), you could also use the method described here for it to work on all operating systems)
when i give
ls -l /etc/fonts/conf.d/70-yes-bitmaps.conf
lrwxrwxrwx <snip> /etc/fonts/conf.d/70-yes-bitmaps.conf -> ../conf.avail/70-yes-bitmaps.conf
so for a symbolic link or soft link, how to find the target file's full(absolute path) in python,
If i use
os.readlink('/etc/fonts/conf.d/70-yes-bitmaps.conf')
it outputs
../conf.avail/70-yes-bitmaps.conf
but i need the absolute path not the relative path, so my desired output must be,
/etc/fonts/conf.avail/70-yes-bitmaps.conf
how to replace the .. with the actual full path of the parent directory of the symbolic link or soft link file.
os.path.realpath(path)
os.path.realpath returns the canonical path of the specified filename, eliminating any symbolic links encountered in the path.
As unutbu says, os.path.realpath(path) should be the right answer, returning the canonical path of the specified filename, resolving any symbolic links to their targets. But it's broken under Windows.
I've created a patch for Python 3.2 to fix this bug, and uploaded it to:
http://bugs.python.org/issue9949
It fixes the realpath() function in Python32\Lib\ntpath.py
I've also put it on my server, here:
http://www.burtonsys.com/ntpath_fix_issue9949.zip
Unfortunately, the bug is present in Python 2.x, too, and I know of no fix for it there.
http://docs.python.org/library/os.path.html#os.path.abspath
also joinpath() and normpath(), depending on whether you're in the current working directory, or you're working with things elsewhere. normpath() might be more direct for you.
Specifically:
os.path.normpath(
os.path.join(
os.path.dirname( '/etc/fonts/conf.d/70-yes-bitmaps.conf' ),
os.readlink('/etc/fonts/conf.d/70-yes-bitmaps.conf')
)
)
I recommend using pathlib library for filesystem operations.
import pathlib
x = pathlib.Path('lol/lol/path')
x.resolve()
Documentation for Path.resolve(strict=False): make the path absolute, resolving any symlinks. A new path object is returned.
On windows 10, python 3.5, os.readlink("C:\\Users\PP") where "C:\Users\PP" is a symbolic link (not a junction link) works.
It returns the absolute path to the directory.
This works on Ubuntu 16.04, python 3.5 as well.
The documentation says to use os.path.join():
The result may be either an absolute or relative pathname; if it is relative, it may be converted to an absolute pathname using os.path.join(os.path.dirname(path), result).