メインコンテンツへスキップ
  1. ブログ/

readlinkの「-f」「-m」「-e」の違いと使い分けを図解で解説

·
Linux コマンド Bash
目次

readlinkの「-f」「-m」「-e」の違いと使い分けを図解で解説
readlinkの「-f」「-m」「-e」の違いと使い分けを図解で解説

コマンド早見表
#

解説は不要という方は、以下のコマンドをそのままコピーしてご利用ください。

  • すべての要素が存在する場合のみ絶対パスに変換する
readlink -e <パス>
  • 親フォルダまで存在するパスを絶対パスにする(対象ファイルは存在しなくても可)
readlink -f <パス>
  • 存在しないディレクトリやファイルを含むパスも絶対パスに変換する
readlink -m <パス>

readlinkコマンドとは
#

readlink コマンドは、シンボリックリンクの参照先を表示するためのコマンドです。

また、後述するオプションを指定することで、通常のファイルやディレクトリのパスを正規化し表示することもできます。

readlinkls などの出力と異なり、参照先のパスのみを出力します。

そのため、シェルスクリプトでシンボリックリンクの参照先を取得したい場合や、パスの正規化を行いたい場合などによく利用されます。

このコマンドは、GNU coreutils の一部として提供されています。

以下が readlink コマンドのソースコードです。

GNU coreutils - readlink.c

※上記リンクはGNU公式リポジトリから自動同期されている公式ミラーです。

基本的な使い方
#

初めに readlink コマンドでシンボリックリンクの参照先を確認する例をご紹介します。

たとえば、以下のようにシンボリックリンクを作成したとします。

$ ln -s /tmp/sample.txt example2.txt
$ ls -al example2.txt
lrwxrwxrwx 1 root root 15  5月 15 20:15 example2.txt -> /tmp/sample.txt

ls -al の出力を見ると、example2.txt/tmp/sample.txt を参照していることが分かります。

この状態で readlink コマンドを実行すると、以下のようにシンボリックリンクの参照先だけを表示できます。

$ readlink example2.txt
/tmp/sample.txt

このように、readlink を利用すると、シンボリックリンクの参照先をシンプルに確認できます。

各オプションの違い
#

次に、パスを正規化する際によく使用するオプションの違いをご紹介します。

readlink コマンドには、パスを正規化するための -f-m-e の3種類のオプションがあります。

いずれも指定したパスを正規化して表示するためのオプションですが、存在しないパスをどこまで許容するかが異なります。

以下の図は、/tmp/example/test.txt を例に、各オプションがどの範囲まで存在している必要があるかを示したものとなります。

readlinkオプションの違い
readlinkオプションの違い

各オプションの違いを表にまとめると、以下のようになります。

オプション 途中のパス要素 最後のパス要素
-e 存在が必要 存在が必要
-f 存在が必要 存在しなくてもよい
-m 存在しなくてもよい 存在しなくてもよい

それぞれのオプションについては、次のセクションで詳しくご紹介します。

-e オプション
#

-e は、指定したパスのすべての要素が存在する場合のみ、正規化したパスを表示するオプションとなります。

たとえば、/tmp/example/test.txt が存在している場合、以下のように絶対パスが表示されます。

$ readlink -e /tmp/example/test.txt
/tmp/example/test.txt

一方、最後の test.txt が存在しない場合は以下のように何も表示されません。

$ readlink -e /tmp/example/test.txt

-f オプション
#

-f は、途中のディレクトリが存在していれば、最後のファイルやディレクトリが存在しない場合でも、正規化したパスを表示するオプションとなります。

たとえば、/tmp/example ディレクトリが存在している場合、test.txt が存在していなくても以下のように絶対パスが表示されます。

$ readlink -f /tmp/example/test.txt
/tmp/example/test.txt

一方、途中のディレクトリである /tmp/example が存在しない場合は何も表示されません。

$ readlink -f /tmp/example/test.txt

-f は、親ディレクトリが存在している前提で、作成予定のファイルパスを正規化したい場合などに適しています。

-m オプション
#

-m は、途中のディレクトリや最後のファイル・ディレクトリが存在しない場合でも、正規化したパスを表示するオプションです。

たとえば、/tmp/example ディレクトリや test.txt が存在していない場合でも、以下のように絶対パスが表示されます。

$ readlink -m /tmp/example/test.txt
/tmp/example/test.txt

また、... を含むパスも正規化されます。

$ readlink -m /tmp/example/../example2/test.txt
/tmp/example2/test.txt

-m は、存在確認を行わず、パス文字列として正規化したい場合に適しています。

そのため、これから作成するディレクトリやファイルのパスを扱う場合によく利用されます。

使い分けの基準
#

ここまで解説したように、-f-m-e はいずれもパスを正規化するためのオプションですが、用途によって使い分ける必要があります。

迷った場合は、以下の表を参考にしてください。

ケース 推奨オプション
実在するファイルやディレクトリのみを扱いたい -e
親ディレクトリは存在するが、ファイルは未作成の可能性がある -f
親ディレクトリも未作成の可能性がある -m
シンボリックリンクの実体パスを取得したい -f または -e
パスの存在確認は不要で、正規化したい -m

一般的なシェルスクリプトでは、シンボリックリンクの解決や絶対パスの取得を行う目的で -f が利用されるケースが多くあります。

一方で、指定したパスが実在することを保証したい場合は -e、作成予定のディレクトリやファイルを含むパスを扱いたい場合は -m が適しています。

実用例
#

では実際にどのようなケースでこれらのコマンドが活用されるかの例をご紹介します。

シェルスクリプト自身のパスを取得する
#

シェルスクリプト内で自身の絶対パスを取得したい場合は、以下のように -f を使用する方法が有効です。

SCRIPT_PATH=$(readlink -f "$0")

この処理により、スクリプトファイル等のパスを正規化して取得できます。

また、シンボリックリンク経由で実行された場合も、リンク先をたどったパスを取得することができます。

SCRIPT_DIR=$(dirname "$(readlink -f "$0")")

実在するファイルだけを対象にする
#

ファイルが存在する場合のみ処理を続行したい場合は、以下のように -e を使用します。

TARGET=$(readlink -e "$1") || {
  echo "指定されたパスは存在しません"
  exit 1
}

-e は最後のパス要素まで存在している必要があるため、存在確認を兼ねた処理に利用することができます。

作成予定のファイルパスを取得する
#

親ディレクトリが存在しており、その配下にファイルを作成する予定であれば、以下のように -f を使用します。

OUTPUT_PATH=$(readlink -f /var/log/test.log)

/var/log が存在していれば、test.log がまだ存在していなくても絶対パスを取得することができます。

未作成ディレクトリを含むパスを取得する
#

親ディレクトリもまだ存在しない可能性がある場合は、以下のように -m を使用します。

OUTPUT_PATH=$(readlink -m ./output/test.log)

./output ディレクトリが存在しない場合でも、正規化された絶対パスを取得できます。

まとめ
#

readlink-f-m-e は非常に似ていますが、存在しないパスを許容する範囲が異なります。

存在確認を厳密に行いたい場合は -e、未作成パスを含めて正規化したい場合は -m、親ディレクトリが存在する前提で通常の正規化を行いたい場合は -f が適しています。

用途に応じて各オプションを使い分けることで、シェルスクリプトでも安全にパスを扱いやすくなります。

ぜひ活用してみてください。

関連記事

curlの--resolveオプションでDNSを使わずにリクエストを送る方法
Linux Curl コマンド DNS
Linuxのfindコマンドで検索する階層を指定する方法(-maxdepth・-mindepth)
Linux コマンド Find
Linuxのsortコマンドで重複行を削除する方法(sort -u / uniq)
Linux コマンド Sort Uniq
Linuxのrmdirで中身ごと削除できない場合に削除する方法(rm -r)
Linux コマンド Rm Rmdir
grepでバイナリファイルを除外する方法|-Iオプションの使い方
Grep コマンド AlmaLinux Linux
lsofとは?Linuxでファイルオープン数を調べる基本コマンド解説
Linux コマンド Lsof