web-dev-qa-db-ja.com

「os.symlink」と「ln -s」

Dir2内のdir1(ファイルまたはディレクトリ)のすべてのアイテムにシンボリックリンクを作成する必要があります。 dir2は既に存在し、シンボリックリンクではありません。 Bashでは、これを簡単に実現できます。

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

しかし、python using 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を使用してこれを実行できるかどうかを知りたいと思います。

35
jurgenreza

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/を実行するとどのように機能しますか?あなたのShellは、ワイルドカードを複数の引数に変換することで機能します。ワイルドカードを使用してexecコマンドだけをlnすると、*という名前の単一のソースがそのディレクトリ内のすべてのファイルではなく、/home/guest/dir1/で検索されます。

Pythonに相当します(2つのレベルを混合し、シェルで可能なチルダ、環境変数、コマンド置換など、他の多くのケースを無視してもかまわない場合) ):

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と同等の処理を行いたい」と言っているようなものです。または、そのことに関しては、Shellが私のためにグロブすることなく、ln -s /home/guest/dir1/* /home/guest/dir2/と同等のことをしたいです。」

正解は、globfnmatch、またはos.listdirに正規表現を加えたもの、または任意のものを使用することです。

notos.walkを使用します。これはrecursiveを行うためですファイルシステムウォークなので、Shell *展開にも近くありません。

57
abarnert

*はシェル拡張パターンです。この場合、「/home/guest/dir1/で始まるすべてのファイル」を指定します。

しかし、それはこのパターンを展開するシェルの役割一致するファイルです。 lnコマンドではありません。

ただし、os.symlinkはシェルではなく、OS呼び出しです。したがって、シェル拡張パターンをサポートしていません。スクリプトでその作業を行う必要があります。

そのためには、os.walk、またはos.listdirを使用できます。他の回答に示されているように、適切な呼び出しは、何をしたいかによって異なります。 (os.walk*と同等ではありません)


納得させるには:端末のUnixマシンでpython -c "import sys; print sys.argv" *というコマンドを実行します。マッチングを行っているのはシェルであることがわかります。

14
Thomas Orozco

@abarnertが示唆するように、*を認識し、dir1内のすべてのアイテムで置き換えるのはシェルです。したがって、os.listdirを使用することが最良の選択だと思います。

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