문제

내가 전화하면 os.stat() 깨진에 symlink, 파이썬은 OSError 예외.이는 이를 찾는 데 유용합니다.그러나 몇 가지 다른 이유가 있습니다. os.stat() 비슷한 예외가 발생할 수 있습니다.파손을 감지하는 더 정확한 방법이 있습니까? symlinks Linux에서 Python을 사용합니까?

도움이 되었습니까?

해결책

일반적인 Python 속담은 허락보다 용서를 구하는 것이 더 쉽다는 것입니다.나는 실생활에서 이 말을 좋아하지는 않지만 많은 경우에 적용됩니다.일반적으로 동일한 파일에 대해 두 개의 시스템 호출을 연결하는 코드는 피하고 싶을 것입니다. 왜냐하면 코드의 두 호출 사이에 파일에 어떤 일이 일어날지 모르기 때문입니다.

전형적인 실수는 다음과 같은 것을 쓰는 것입니다.:

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

두 번째 호출(os.unlink)은 if 테스트 후에 다른 것이 이를 삭제하고 예외를 발생시키며 나머지 함수 실행을 중지하는 경우 실패할 수 있습니다.(실생활에서는 이런 일이 발생하지 않는다고 생각할 수도 있지만 지난주에 우리 코드베이스에서 이와 같은 버그를 또 발견했습니다. 이는 몇몇 프로그래머가 머리를 긁적이며 '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

다른 팁

os.lstat() 도움이 될 수 있습니다.lstat()가 성공하고 stat()가 실패하면 링크가 끊어진 것일 수 있습니다.

이것은 원자적이지는 않지만 작동합니다.

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

실제로 RTFM(환상적인 매뉴얼을 읽으면서) 우리는 알겠습니다

os.path.exists(경로)

path가 기존 경로를 참조하는 경우 True를 반환합니다.깨진 심볼릭 링크에 대해서는 False를 반환합니다.

또한 다음과 같이 말합니다.

일부 플랫폼에서는 경로가 물리적으로 존재하더라도 요청된 파일에 대해 os.stat()을 실행할 수 있는 권한이 부여되지 않은 경우 이 함수가 False를 반환할 수 있습니다.

따라서 권한이 걱정된다면 다른 조항을 추가해야 합니다.

Python 없이 하드링크 테스트를 언급할 수 있나요?/bin/test에는 파일이 inode를 공유할 때 참인 FILE1 -ef FILE2 조건이 있습니다.

따라서 다음과 같은 것 find . -type f -exec test \{} -ef /path/to/file \; -print 특정 파일에 대한 하드 링크 테스트에 사용됩니다.

나를 읽게 만드는 것은 man test 그리고 언급된 내용은 -L 그리고 -h 둘 다 하나의 파일에서 작동하고 해당 파일이 심볼릭 링크이면 true를 반환하지만 대상이 누락되었는지는 알려주지 않습니다.

나는 그것을 찾았다 head -0 FILE1 종료 코드를 반환합니다 0 파일을 열 수 있고 1 그렇지 않은 경우 일반 파일에 대한 심볼릭 링크의 경우 대상을 읽을 수 있는지 여부에 대한 테스트로 작동합니다.

OS.경로

realpath()를 사용하여 심볼릭 링크가 가리키는 내용을 얻은 다음 is file을 사용하여 유효한 파일인지 확인하려고 시도할 수 있습니다.

(지금은 시도해 볼 수 없으므로 직접 사용해 보고 결과를 확인해야 합니다.)

저는 파이썬 전문가는 아니지만 os.readlink()처럼 보이나요?내가 Perl에서 사용할 논리는 readlink()를 사용하여 대상을 찾고 stat()를 사용하여 대상이 존재하는지 테스트하는 것입니다.

편집하다:나는 readlink를 데모하는 Perl을 사용했습니다.나는 Perl의 stat 및 readlink와 Python의 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 >

비슷한 문제가 있었습니다.일부 상위 디렉토리에서 발생하는 경우에도 깨진 심볼릭 링크를 잡는 방법은 무엇입니까?또한 (상당히 많은 수의 파일을 처리하는 응용 프로그램에서) 모든 내용을 기록하고 싶었지만 너무 많이 반복하지는 않았습니다.

단위 테스트를 포함하여 제가 생각해낸 내용은 다음과 같습니다.

파일유틸.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()
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top