Wenn ich os.stat()
auf einem defekten symlink
aufrufen, löst Python eine OSError
Ausnahme. Dies macht es nützlich, sie zu finden. Es gibt jedoch einige andere Gründe, warum os.stat()
eine ähnliche Ausnahme auslösen könnte. Gibt es einen genaueren Weg, um mit Python unter Linux die defekte symlinks
zu erkennen?Finden Sie gebrochene Symlinks mit Python
Antwort
Ein gemeinsamer Python sagen ist, dass es einfacher ist, um Vergebung zu bitten, als Genehmigung. Obwohl ich im wirklichen Leben kein Fan von dieser Aussage bin, trifft es in vielen Fällen zu. Normalerweise möchten Sie Code vermeiden, der zwei Systemaufrufe für dieselbe Datei verknüpft, weil Sie nie wissen, was zwischen Ihren beiden Aufrufen in Ihrem Code passieren wird.
Ein typischer Fehler ist so etwas wie zu schreiben:
if os.path.exists(path):
os.unlink(path)
Der zweite Aufruf (os.unlink) kann fehlschlagen, wenn etwas anderes es nach dem if-Test gelöscht, eine Ausnahme auslösen, und den Rest stoppen Ihrer Funktion ausführen.(Du denkst vielleicht, dass das im wirklichen Leben nicht passiert, aber wir haben letzte Woche einen anderen Bug aus unserer Codebase gefischt - und es war die Art von Bug, der ein paar Programmierer am Kopf kratzte und 'Heisenbug' für die letzten Monate)
in Ihrem speziellen Fall also würde ich wahrscheinlich tun:
try:
os.stat(path)
except OSError, e:
if e.errno == errno.ENOENT:
print 'path %s does not exist or is a broken symlink' % path
else:
raise e
Der Ärger ist hier, dass stat die gleiche Fehlercode für einen Symlink zurückgibt, die einfach nicht da ist und ein gebrochenes Symlink.
Also, ich denke, Sie haben keine andere Wahl als die Unteilbarkeit zu brechen, und so etwas wie
if not os.path.exists(os.readlink(path)):
print 'path %s is a broken symlink' % path
Kann ich das Testen für Hardlinks ohne Python erwähnen?/bin/test hat die Bedingung FILE1 -ef FILE2, die erfüllt ist, wenn Dateien einen Inode teilen.
Daher funktioniert etwas wie find . -type f -exec test \{} -ef /path/to/file \; -print
für harte Verbindungstests zu einer bestimmten Datei.
Das bringt mich zu man test
Lesen und die Erwähnungen von -L
und -h
, die beide arbeiten auf eine Datei und true zurück, wenn die Datei ein symbolischer Link ist, aber die Sie nicht sagen, ob das Ziel fehlt.
Ich fand, dass head -0 FILE1
würde einen Exit-Code von 0
zurück, wenn die Datei geöffnet werden kann und ein 1
wenn es nicht kann, was im Fall eines symbolischen Link zu einer normalen Datei als Test arbeitet dafür, ob Ziel es ist möglich gelesen werden.
Ich bin kein Python-Typ, aber es sieht aus wie os.readlink()? Die Logik, die ich in Perl verwenden würde, ist die Verwendung von readlink(), um das Ziel zu finden, und die Verwendung von stat(), um zu testen, ob das Ziel existiert.
Edit: Ich schlug einige Perl, die Demos Readlink. Ich glaube, die Perl-Stat und Readlink und Pythons os.stat() und os.readlink() sind beide Wrapper für die Systemaufrufe, so sollte dies vernünftig übersetzen und Proof of Concept-Code:
wembley 0 /home/jj33/swap > cat p
my $f = shift;
while (my $l = readlink($f)) {
print "$f -> $l\n";
$f = $l;
}
if (!-e $f) {
print "$f doesn't exist\n";
}
wembley 0 /home/jj33/swap > ls -l | grep ^l
lrwxrwxrwx 1 jj33 users 17 Aug 21 14:30 link -> non-existant-file
lrwxrwxrwx 1 root users 31 Oct 10 2007 mm -> ../systems/mm/20071009-rewrite//
lrwxrwxrwx 1 jj33 users 2 Aug 21 14:34 mmm -> mm/
wembley 0 /home/jj33/swap > perl p mm
mm -> ../systems/mm/20071009-rewrite/
wembley 0 /home/jj33/swap > perl p mmm
mmm -> mm
mm -> ../systems/mm/20071009-rewrite/
wembley 0 /home/jj33/swap > perl p link
link -> non-existant-file
non-existant-file doesn't exist
wembley 0 /home/jj33/swap >
os.lstat() kann hilfreich sein . Wenn lstat() erfolgreich ist und stat() fehlschlägt, handelt es sich wahrscheinlich um einen fehlerhaften Link.
Sie können versuchen, mit realpath() zu bekommen, was der Symlink auf, dann zu bestimmen versuchen herauszufinden, ob es eine gültige Datei ist, ist die Verwendung der Datei.
(Ich bin nicht in der Lage, dass in dem Moment zu versuchen, so dass Sie mit ihm spielen, um müssen und sehen, was Sie erhalten)
Das ist nicht atomar ist, aber es funktioniert.
os.path.islink(filename) and not os.path.exists(filename)
Tat von RTFM (die fantastische Handbuch zu lesen) sehen wir
os.path.exists (Pfad)
Return True, wenn Pfad zu einem vorhandenen Pfad verweist. Gibt für fehlerhafte symbolische Links False zurück.
Er sagt auch:
Auf einigen Plattformen diese Funktion Falsch zurückgeben kann, wenn die Erlaubnis nicht erteilt wird os.stat() auf der gewünschten Datei auszuführen, auch wenn der Pfad vorhanden ist physisch.
Wenn Sie sich also Sorgen um Berechtigungen machen, sollten Sie weitere Klauseln hinzufügen.
+1 für 'os.path.islink (Dateiname) und nicht os.path.exists (Dateiname)' was mir geholfen hat, und dafür, dass das F in RTFM Fantastic ist. – esmit
Ich hatte ein ähnliches Problem: Wie man gebrochene symbolische Links fängt, selbst wenn sie in einem Elternteil vorkommen? Ich wollte auch alle von ihnen (in einer Anwendung, die sich mit einer ziemlich großen Anzahl von Dateien beschäftigt) protokollieren, aber ohne zu viele Wiederholungen.
Hier ist, was ich, einschließlich Komponententests, kam.
fileutil.py:
import os
from functools import lru_cache
import logging
logger = logging.getLogger(__name__)
@lru_cache(maxsize=2000)
def check_broken_link(filename):
"""
Check for broken symlinks, either at the file level, or in the
hierarchy of parent dirs.
If it finds a broken link, an ERROR message is logged.
The function is cached, so that the same error messages are not repeated.
Args:
filename: file to check
Returns:
True if the file (or one of its parents) is a broken symlink.
False otherwise (i.e. either it exists or not, but no element
on its path is a broken link).
"""
if os.path.isfile(filename) or os.path.isdir(filename):
return False
if os.path.islink(filename):
# there is a symlink, but it is dead (pointing nowhere)
link = os.readlink(filename)
logger.error('broken symlink: {} -> {}'.format(filename, link))
return True
# ok, we have either:
# 1. a filename that simply doesn't exist (but the containing dir
does exist), or
# 2. a broken link in some parent dir
parent = os.path.dirname(filename)
if parent == filename:
# reached root
return False
return check_broken_link(parent)
Unit-Tests:
import logging
import shutil
import tempfile
import os
import unittest
from ..util import fileutil
class TestFile(unittest.TestCase):
def _mkdir(self, path, create=True):
d = os.path.join(self.test_dir, path)
if create:
os.makedirs(d, exist_ok=True)
return d
def _mkfile(self, path, create=True):
f = os.path.join(self.test_dir, path)
if create:
d = os.path.dirname(f)
os.makedirs(d, exist_ok=True)
with open(f, mode='w') as fp:
fp.write('hello')
return f
def _mklink(self, target, path):
f = os.path.join(self.test_dir, path)
d = os.path.dirname(f)
os.makedirs(d, exist_ok=True)
os.symlink(target, f)
return f
def setUp(self):
# reset the lru_cache of check_broken_link
fileutil.check_broken_link.cache_clear()
# create a temporary directory for our tests
self.test_dir = tempfile.mkdtemp()
# create a small tree of dirs, files, and symlinks
self._mkfile('a/b/c/foo.txt')
self._mklink('b', 'a/x')
self._mklink('b/c/foo.txt', 'a/f')
self._mklink('../..', 'a/b/c/y')
self._mklink('not_exist.txt', 'a/b/c/bad_link.txt')
bad_path = self._mkfile('a/XXX/c/foo.txt', create=False)
self._mklink(bad_path, 'a/b/c/bad_path.txt')
self._mklink('not_a_dir', 'a/bad_dir')
def tearDown(self):
# Remove the directory after the test
shutil.rmtree(self.test_dir)
def catch_check_broken_link(self, expected_errors, expected_result, path):
filename = self._mkfile(path, create=False)
with self.assertLogs(level='ERROR') as cm:
result = fileutil.check_broken_link(filename)
logging.critical('nothing') # trick: emit one extra message, so the with assertLogs block doesn't fail
error_logs = [r for r in cm.records if r.levelname is 'ERROR']
actual_errors = len(error_logs)
self.assertEqual(expected_result, result, msg=path)
self.assertEqual(expected_errors, actual_errors, msg=path)
def test_check_broken_link_exists(self):
self.catch_check_broken_link(0, False, 'a/b/c/foo.txt')
self.catch_check_broken_link(0, False, 'a/x/c/foo.txt')
self.catch_check_broken_link(0, False, 'a/f')
self.catch_check_broken_link(0, False, 'a/b/c/y/b/c/y/b/c/foo.txt')
def test_check_broken_link_notfound(self):
self.catch_check_broken_link(0, False, 'a/b/c/not_found.txt')
def test_check_broken_link_badlink(self):
self.catch_check_broken_link(1, True, 'a/b/c/bad_link.txt')
self.catch_check_broken_link(0, True, 'a/b/c/bad_link.txt')
def test_check_broken_link_badpath(self):
self.catch_check_broken_link(1, True, 'a/b/c/bad_path.txt')
self.catch_check_broken_link(0, True, 'a/b/c/bad_path.txt')
def test_check_broken_link_badparent(self):
self.catch_check_broken_link(1, True, 'a/bad_dir/c/foo.txt')
self.catch_check_broken_link(0, True, 'a/bad_dir/c/foo.txt')
# bad link, but shouldn't log a new error:
self.catch_check_broken_link(0, True, 'a/bad_dir/c')
# bad link, but shouldn't log a new error:
self.catch_check_broken_link(0, True, 'a/bad_dir')
if __name__ == '__main__':
unittest.main()
- 1. Beachtet Python Symlinks?
- 2. Finden Sie Montag mit Python
- 3. Gebrochene Referenzen in Virtualenvs
- 4. Mercurial Symlinks unter Windows
- 5. Nginx folgt nicht Symlinks
- 6. Renci SSH.NET: So erstellen Sie Symlinks?
- 7. Symlinks in setuptools ignorieren MANIFEST.in?
- 8. Erhalten Sie gebrochene (oder weiche) Einschränkungen
- 9. Finden Sie Reim mit NLTK in Python
- 10. Symlinks Korruption in iOS benutzerdefinierten Rahmen
- 11. Folgen Symlinks in SVN
- 12. Windows 7 mit Symlinks in cmd
- 13. Gebrochene Fremdschlüssel in Rails
- 14. Vagrant freigegebenen Ordner. Symlinks
- 15. Gebrochene Java Mac 10.6
- 16. NPM node_modules/.bin symlinks
- 17. Gebrochene Zeichenfolge in Ausnahme?
- 18. Symlinks und Dateiumleitung
- 19. Symlinks auf Windows
- 20. Gebrochene PIP3 und easy_install3: DistributionNotFound
- 21. Instagram API - Gebrochene URL?
- 22. Synchron AJAX (gebrochene Versprechen)
- 23. subrepo, hg klon und symlinks
- 24. Finden Sie Bilder mit ähnlicher Farbpalette mit Python
- 25. Finden Sie die beste Fitparameter Python
- 26. Python: Finden Sie Differenz zwischen zwei Wörterlisten
- 27. Rsync Symlinks zu PHP-Dateien
- 28. Erkennen eines Symlinks in Java
- 29. Wie kann Ruby's Find.find Symlinks folgen?
- 30. Finden Sie Hyperlinks in Text mit Python (twitter verwandt)
Readlink auch errno == ENOTDIR wenn der Symlink missuses eine Datei als Verzeichnis festlegen. –
os.readlink (Pfad) erhält möglicherweise nicht den tatsächlichen Pfad, wenn dem Pfad 'link' ein relativer Pfad zu seinem Ziel zugewiesen wird. Wenn Pfad beispielsweise mit '../target' verknüpft ist, gibt os.path.exists (os.readlink (Pfad)) false zurück, weil Sie den Pfad nicht im Pfad angeben, in dem sich die Verknüpfung befindet Ihr oberes Verzeichnis hat keine Datei oder keinen Ordner namens 'target'. Eine sichere Möglichkeit, dies zu vermeiden, ist os.path.exists (os.path.realpath (path)). – AplusG
Auch das ist nicht gut genug. realpath interpretiert den Pfad des Symlinks relativ zum aktuellen laufenden Verzeichnis des aktuell laufenden Skripts, während ein symbolischer Link vom Betriebssystem relativ zu dem Ordner interpretiert wird, in dem sich der symbolische Link befindet. Was Sie tun müssen, ist etwas wie folgt zu tun: link_target = os.readlink (Pfad) dir = os.path.dirname (Pfad) wenn nicht os.path.isabs (link_target): link_target = os.path.join (dir, link_target) wenn os.path.exists (link_target): # tun, was Sie mit diesem schlechten symlink –