Подтвердить что ты не робот

`os.symlink` vs` ln -s`

Мне нужно создать символическую ссылку для каждого элемента dir1 (файл или каталог) внутри dir2. dir2 уже существует и не является символической ссылкой. В Bash я легко могу добиться этого:

ln -s/home/guest/dir1/*/home/guest/dir2/

Но в Python с использованием os.symlink я получаю ошибку:

>>> os.symlink('/home/guest/dir1/*', '/home/guest/dir2/')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OSError: [Errno 17] File exist

Я знаю, что могу использовать subprocess и запустить команду ln. Я не хочу этого решения.

Я также знаю, что возможны обходные пути с использованием os.walk или glob.glob, но я хочу знать, возможно ли это сделать с помощью os.symlink.

4b9b3361

Ответ 1

os.symlink создает одну символическую ссылку.

ln -s создает несколько символических ссылок (если его последний аргумент является каталогом и существует более одного источника). Эквивалент Python выглядит примерно так:

dst = args[-1]
for src in args[:-1]:
    os.symlink(src, os.path.join(dst, os.path.dirname(src)))

Итак, как это работает, когда вы делаете ln -s /home/guest/dir1/* /home/guest/dir2/? Ваша оболочка делает это, превращая шаблон в несколько аргументов. Если бы вы просто указали exec команду ln с подстановочным знаком, она бы искала один источник с буквальным названием * в /home/guest/dir1/, а не все файлы в этом каталоге.

Эквивалент Python выглядит примерно так (если вы не возражаете смешивать два уровня вместе и игнорировать множество других случаев - тильды, переменные env, подстановку команд и т.д., Которые возможны в оболочке):

dst = args[-1]
for srcglob in args[:-1]:
    for src in glob.glob(srcglob):
        os.symlink(src, os.path.join(dst, os.path.dirname(src)))

Вы не можете сделать это с одним os.symlink - любой его частью - потому что он этого не делает. Это как сказать: "Я хочу сделать эквивалент find . -name foo, используя os.walk без фильтрации по имени". Или, если на то пошло, я хочу сделать эквивалент ln -s /home/guest/dir1/* /home/guest/dir2/ без оболочки, для меня ".

Правильный ответ - использовать glob, или fnmatch, или os.listdir, и регулярное выражение, или все, что вы предпочитаете.

Не используйте os.walk, потому что это делает рекурсивное обход файловой системы, так что это даже близко не к расширению оболочки *.

Ответ 2

* - это шаблон расширения оболочки, который в вашем случае обозначает "все файлы, начинающиеся с /home/guest/dir1/".

Но это ваша роль оболочки, чтобы расширить этот шаблон до файлов, которые он соответствует. Не команда ln.

Но os.symlink не является оболочкой, это вызов ОС - следовательно, он не поддерживает шаблоны расширения оболочки. Вам нужно будет выполнить эту работу в script.

Для этого вы можете использовать os.walk или os.listdir. Как указано в другом ответе, соответствующий вызов будет зависеть от того, что вы хотите сделать. (os.walk не будет эквивалентом *)


Чтобы убедить себя: запустите эту команду на машине Unix в вашем терминале: python -c "import sys; print sys.argv" *. Вы увидите, что это оболочка, которая выполняет сопоставление.

Ответ 3

Как было предложено @abarnert, это оболочка, которая распознает * и заменяет ее всеми элементами insir dir1. Поэтому я думаю, что использование os.listdir - лучший выбор:

for item in os.listdir('/home/guest/dir1'):
    os.symlink('/home/guest/dir1/' + item, '/home/guest/dir2/' + item)