Βρείτε σπασμένα συμβολικών συνδέσμων με την Python

ψήφοι
16

Αν καλώ os.stat()σε ένα σπασμένο symlink, python ρίχνει μια OSErrorεξαίρεση. Αυτό το καθιστά χρήσιμο για την εύρεση τους. Ωστόσο, υπάρχουν και κάποιοι άλλοι λόγοι που os.stat()θα μπορούσε να ρίξει μια παρόμοια εξαίρεση. Είναι ένας πιο ακριβής τρόπος για την ανίχνευση σπασμένα εκεί symlinksμε την Python στο Linux;

Δημοσιεύθηκε 21/08/2008 στις 20:00
πηγή χρήστη
Σε άλλες γλώσσες...                            


7 απαντήσεις

ψήφοι
3

Μπορώ να αναφέρω δοκιμών για hardlinks χωρίς πύθωνα; / Bin / δοκιμή έχει η κατάσταση ΑΡΧΕΙΟ1 -ef ΑΡΧΕΙΟ2 που είναι αλήθεια, όταν τα αρχεία μοιράζονται ένα inode.

Ως εκ τούτου, κάτι σαν find . -type f -exec test \{} -ef /path/to/file \; -printτα έργα για τη δοκιμή δύσκολο σύνδεση με ένα συγκεκριμένο αρχείο.

Που με φέρνει στην ανάγνωση man testκαι τις αναφορές του -Lκαι -hτα οποία εργάζονται και οι δύο σε ένα αρχείο και να επιστρέψει true αν το αρχείο είναι ένα συμβολικό δεσμό, ωστόσο, ότι δεν σας πει εάν ο στόχος λείπει.

Βρήκα ότι head -0 FILE1θα επιστρέψουν τον κωδικό εξόδου 0, εάν το αρχείο μπορεί να ανοίξει και 1αν δεν μπορεί, η οποία στην περίπτωση της μια συμβολική σύνδεση με ένα κανονικό αρχείο λειτουργεί ως δοκιμή για το αν είναι στόχος μπορεί να διαβάσει.

Απαντήθηκε 21/08/2008 στις 20:13
πηγή χρήστη

ψήφοι
1

Δεν είμαι ένας τύπος python αλλά μοιάζει os.readlink (); Η λογική που θα χρησιμοποιήσει στην perl είναι η χρήση readlink () για να βρει το στόχο και τη χρήση stat () για να ελέγξετε για να δείτε αν υπάρχει ο στόχος.

Επεξεργασία: Χτύπησα μερικά Perl που demos readlink. Πιστεύω stat perl και readlink και os.stat πύθωνα του () και os.readlink () είναι και οι δύο περιτυλίγματα για τις κλήσεις του συστήματος, έτσι αυτό θα πρέπει να μεταφράσει λογικό και αποδεικτικό κωδικό έννοια:

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 >
Απαντήθηκε 21/08/2008 στις 20:14
πηγή χρήστη

ψήφοι
11

os.lstat () μπορεί να είναι χρήσιμη. Αν lstat () καταφέρνει και stat () αποτύχει, τότε μάλλον ένα link.

Απαντήθηκε 21/08/2008 στις 20:15
πηγή χρήστη

ψήφοι
2

os.path

Μπορείτε να δοκιμάστε να χρησιμοποιήσετε realpath () για να πάρει ό, τι τα σημεία σύνδεσμος σε, στη συνέχεια προσπαθεί να καθορίσει αν είναι ένα έγκυρο αρχείο χρησιμοποιώντας είναι αρχείο.

(Δεν είμαι σε θέση να δοκιμάσετε ότι από αυτή τη στιγμή, έτσι θα πρέπει να παίζουν με αυτό και να δούμε τι παίρνετε)

Απαντήθηκε 21/08/2008 στις 20:19
πηγή χρήστη

ψήφοι
20

Ένα ρητό κοινή Python είναι ότι είναι πιο εύκολο να ζητήσει συγχώρεση από άδεια. Αν και δεν είμαι οπαδός αυτής της δήλωσης στην πραγματική ζωή, αυτό δεν ισχύει σε πολλές περιπτώσεις. Συνήθως θέλετε να αποφύγετε κωδικό που αλυσίδες δύο συστήματος ζητά από το ίδιο αρχείο, γιατί ποτέ δεν ξέρεις τι θα συμβεί στο αρχείο ανάμεσα σε δύο κλήσεις σας στον κώδικά σας.

Ένα τυπικό λάθος είναι να γράψει κάτι σαν :

if os.path.exists(path):
    os.unlink(path)

Η δεύτερη πρόσκληση (os.unlink) μπορεί να αποτύχει αν κάτι άλλο που διαγράφονται μετά, αν το τεστ, να αυξήσει μια εξαίρεση, και να σταματήσει το υπόλοιπο της λειτουργίας σας από την εκτέλεση. (Μπορείτε να σκεφτείτε αυτό δεν συμβαίνει στην πραγματική ζωή, αλλά μόλις αλιεύονται ένα άλλο bug, όπως ότι από τη βάση κώδικα μας την περασμένη εβδομάδα - και αυτό ήταν το είδος των σφαλμάτων που άφησε μερικά προγραμματιστές ξύσιμο το κεφάλι τους και υποστηρίζοντας «heisenbug» για το τελευταίους μήνες)

Έτσι, στην περίπτωσή σας, εγώ θα μπορούσε πιθανότατα να κάνετε:

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

Η ενόχληση εδώ είναι ότι stat επιστρέφει τον ίδιο κωδικό σφάλματος για ένα συμβολικό σύνδεσμο που απλά δεν υπάρχει και ένα σπασμένο δεσμός.

Έτσι, υποθέτω ότι δεν έχουν άλλη επιλογή από το να σπάσει την ατομικότητα, και να κάνουμε κάτι σαν

if not os.path.exists(os.readlink(path)):
    print 'path %s is a broken symlink' % path
Απαντήθηκε 25/08/2008 στις 22:32
πηγή χρήστη

ψήφοι
8

Αυτό δεν είναι ατομικό, αλλά λειτουργεί.

os.path.islink(filename) and not os.path.exists(filename)

Πράγματι, από RTFM (διαβάζοντας το φανταστικό εγχειρίδιο) βλέπουμε

os.path.exists (διαδρομή)

Επιστροφή True αν η διαδρομή αναφέρεται σε μια υπάρχουσα διαδρομή. Επιστρέφει False για σπασμένα συμβολικούς δεσμούς.

Λέει επίσης:

Σε ορισμένες πλατφόρμες, αυτή η λειτουργία μπορεί να επιστρέψει False εάν η άδεια δεν χορηγείται για την εκτέλεση os.stat () στο αρχείο που ζητήθηκε, ακόμα και αν υπάρχει φυσικά η διαδρομή.

Έτσι, εάν είστε ανησυχούν για τα δικαιώματα, θα πρέπει να προσθέσετε άλλες διατάξεις.

Απαντήθηκε 28/06/2015 στις 16:49
πηγή χρήστη

ψήφοι
0

Είχα ένα παρόμοιο πρόβλημα: πώς να πιάσει σπασμένα symlinks, ακόμα και όταν αυτά συμβαίνουν σε κάποια μητρική dir; Ήθελα επίσης να συνδεθείτε όλα αυτά (σε μια εφαρμογή που ασχολούνται με ένα αρκετά μεγάλο αριθμό αρχείων), χωρίς όμως πάρα πολλές επαναλήψεις.

Εδώ είναι αυτό που ήρθε με, συμπεριλαμβανομένων των δοκιμών μονάδα.

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)

δοκιμές Μονάδα:

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()
Απαντήθηκε 27/10/2016 στις 01:49
πηγή χρήστη

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more