シェルスクリプトでのシンボリックリンクの解決方法
Unix系システムでシンボリックリンク(またはシンリンク)を扱うのは、特にシンリンクが指し示す実際のパスを知りたいときには難しいことがあります。シェルスクリプトを書いていて、中間のシンリンクを解決した後にターゲットのフルパスを特定する必要がある場合、正しい場所にいます。このブログ投稿では、これを効率良く達成する方法を説明します。
問題の理解
シンボリックリンクfoo
が別のディレクトリbar
を指し示している状況を想像してみてください。cd foo
やpwd
のようなコマンドを実行しても、シェルは基盤となる構造を明確に示さないため、ターゲットへのフルパスを導き出すのが難しいことがあります。
例えば、次のような出力が得られます。
ls -ld foo bar
drwxr-xr-x 2 greg greg 68 Aug 11 22:36 bar
lrwxr-xr-x 1 greg greg 3 Aug 11 22:36 foo -> bar
以下のコマンドを実行すると:
cd foo
pwd
出力は単に/Users/greg/tmp/foo
となり、foo
が指し示す実際のパスである/Users/greg/tmp/bar
を知りたい場合、あまり役に立ちません。
解決策
幸いなことに、シェルスクリプトにおいてシンリンクを解決するのに役立つ組み込みコマンドがあります。Cプログラミングに深入りする必要なく、次のように行うことができます。
pwd
コマンドの使用
pwd -P
コマンドは、現在の作業ディレクトリを表示するために使用され、すべてのシンリンクを解決してターゲットの絶対パスを提供します。次のコマンドを実行すると:
pwd -P
シンリンクを解決した後のフルパスが返されます。
getcwd
の使用
別の方法は、Cのunistd.h
ライブラリからgetcwd
関数を利用することです。ただし、スクリプトを書いている場合は、シェルコマンドを利用することができます。getcwd
はpwd -P
と似た動作を持つことを知っておくと良いでしょう。
解決関数の構築
これらのコマンドを関数にラップして作業を楽にすることができます。以下はBashシェルでのシンプルなresolve
関数の例です。
resolve() {
# 提供されたパスを使用して解決
local target=$1
# `readlink -f`はシンリンクを辿って、フルパスを返します
local full_path=$(readlink -f "$target")
echo "$full_path"
}
使用例
次に、単に次のように関数を呼び出します:
resolve "foo"
これにより、次の出力が返されます:
/Users/greg/tmp/bar
このパターンを使えば、シェルスクリプト環境で遭遇した任意のシンリンクのフルパスにアクセスすることができます。
ボーナス: ユーザーホームパスの解決
ティルダ表記(例えば~username
)を使ってホームディレクトリを解決したい場合、Bashはシェルスクリプト内でこれらのパスを自動的に展開するため、resolve
関数と組み合わせてシームレスに利用できます。
結論
シェルスクリプトでシンボリックリンクを解決するのは、複雑である必要はありません。pwd -P
コマンドを利用するか、readlink
を使用するヘルパー関数のようなresolve
を作成することで、ターゲットへのフルパスを効果的に決定できます。このスキルは、Unix系環境で作業する人には不可欠であり、スクリプトをより堅牢で情報量の多いものにします。
シンリンクを適切に管理することで、ディレクトリ構造のナビゲートや複雑なシェルスクリプトの作成時に時間を節約し、混乱を避けることができます。