`OS.lien symbolique` vs `ln-s`
J'ai besoin de créer un lien symbolique pour chaque élément de dir1 (fichier ou répertoire) dans dir2. dir2 existe déjà et n'est pas un lien symbolique. En Bash, je peux facilement y parvenir en:
ln -s /home/guest/dir1/* /home/guest/dir2/
Mais en python en utilisant os.lien symbolique je reçois une erreur:
>>> os.symlink('/home/guest/dir1/*', '/home/guest/dir2/')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OSError: [Errno 17] File exist
Je sais que je peux utiliser subprocess
et exécuter ln
commande. Je ne veux pas que la solution.
Je suis également conscient que des solutions de contournement utilisant os.walk
ou glob.glob
sont possibles, mais je veux savoir s'il est possible de le faire en utilisant os.symlink
.
3 réponses
os.symlink
crée un lien symbolique.
ln -s
crée plusieurs liens symboliques (si son dernier argument est un répertoire et qu'il y a plus d'une source). L'équivalent Python est quelque chose comme:
dst = args[-1]
for src in args[:-1]:
os.symlink(src, os.path.join(dst, os.path.dirname(src)))
Alors, comment ça marche quand vous faites ln -s /home/guest/dir1/* /home/guest/dir2/
? Votre shell fait que cela fonctionne, en transformant le caractère générique en plusieurs arguments. Si vous deviez juste exec
la commande ln
avec un caractère générique, il chercherait une source unique littéralement nommée *
dans /home/guest/dir1/
, pas tous les fichiers dans cela répertoire.
L'équivalent Python est quelque chose comme (si cela ne vous dérange pas de mélanger deux niveaux ensemble et d'ignorer beaucoup d'autres cas-tildes, variables env, substitution de commandes, etc. qui sont possibles à la coquille):
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)))
Vous ne pouvez pas faire cela avec os.symlink
seul-ou partie de celui-ci-parce qu'il ne le fait pas. C'est comme dire "je veux faire l'équivalent de find . -name foo
en utilisant os.walk
sans filtrer sur le nom."Ou, d'ailleurs, je veux faire l'équivalent de ln -s /home/guest/dir1/* /home/guest/dir2/
sans le coquille d'expansion pour moi."
, Le droit de réponse est d'utiliser glob
, ou fnmatch
, ou os.listdir
, plus une regex, ou ce que vous préférez.
Faites Pas utilisez os.walk
, car cela fait une marche récursive du système de fichiers, donc ce n'est même pas proche de l'expansion du shell *
.
*
est un modèle d'extension shell, qui dans votre cas désigne " tous les fichiers commençant par /home/guest/dir1/
".
Mais c'est le rôle de votre shell d'étendre ce modèle aux fichiers qu'il correspond. Pas la commande ln
.
Mais os.symlink
n'est pas un shell, c'est un appel OS - par conséquent, il ne supporte pas les modèles d'extension shell. Vous devrez faire ce travail dans votre script.
Pour ce faire, vous pouvez utiliser os.walk
, ou os.listdir
. Comme indiqué dans l'autre réponse, l'appel sera dépendent de ce que vous voulez faire. (os.walk
ne serait pas l'équivalent de *
)
Pour vous convaincre: exécutez cette commande sur une machine Unix de votre terminal: python -c "import sys; print sys.argv" *
. Vous verrez que c'est le shell qui fait la correspondance.
Comme suggéré par @abarnert c'est le shell qui reconnaît *
et le remplace par tous les éléments insside dir1. Par conséquent, je pense que l'utilisation de os.listdir
est le meilleur choix:
for item in os.listdir('/home/guest/dir1'):
os.symlink('/home/guest/dir1/' + item, '/home/guest/dir2/' + item)