通常のファイルとシンボリックリンクを区別する


22

通常のファイルとシンボリックリンクを区別する必要があるbashスクリプトを書いています。if / test式でこれを行うことができると思ったが、期待どおりに機能しません:

$ touch regular_file
$ test -f regular_file; echo $?
0
$ test -h regular_file; echo $?
1
$ ln -s regular_file symlink
$ test -h symlink; echo $?
0
$ test -f symlink; echo $?
0

何故ですか?そして、どうすればこれを適切に行うことができますか?

回答:


20

テストを少しスクランブルしているように見えます。両方のテストを実行する必要はありません。この場合に必要なのは-h、ファイルがシンボリックリンクであるかどうかを知らせるものだけです。

test -h file && echo "is symlink" || echo "is regular file"

この-fテストでは、オブジェクトがファイルかどうかのみがわかります。これ0は、ディレクトリまたはデバイスノードまたはディレクトリ1へのシンボリックリンクの場合に返されますが、ファイルへのシンボリックリンクでは返されます。

また、ディレクトリではなくファイルへのシンボリックリンクであるかどうかを知る必要がある場合は、両方のテストの結果を少しのロジックと組み合わせる必要があります。


私はドキュメントから理解されるように、差-eとは、-fそれをした-e(任意の型の)ファイルが存在するかどうかを知るために使用し、-fファイルが存在し、通常のファイルであった場合、テストに特異でした。「通常のファイル」とは何かを誤解したようです
。– Nupraptor

1
@Nupraptor:はい、あなたはドキュメントを誤解しました。シンボリックリンクは、ファイルが他の種類のノード(ブロックデバイスノード、キャラクターデバイスノード、ディレクトリなど)である場合とは対照的に、通常のファイルと見なされます。ファイルのタイプを知りたい場合は-h、シンボリックリンク、-p名前付きパイプなどのファイルタイプ固有のテストを実行する必要があります
。-カレブ

次に、パイプでもシンボリックリンクでもないという意味で、ファイルが通常のファイルであるかどうかをテストするにはどうすればよいですか?これについて別の質問を開く必要がありますか?
-Nupraptor

@Nupraptor:唯一の奇妙なケースは、通常のファイルにリンクするシンボリックリンクです。それ以外の場合、通常のファイルとしてテストする場合、それは通常のファイルです。
デビッドシュワルツ

3
test -fディレクトリは、0ではなく1を返します:test -f。; エコー$?(出力1)
多項式

7

@Calebは、シンボリックリンクをテストするだけのスクリプトを作成することについて正しいです。しかし、なぜかに関する部分は省かれ、私は興味がありました。coreutilsのソースコードを見てテストの出力を追跡すると、シンボリックリンクテストを実行するとlstatが使用され、-fテストを使用すると実際にシンボリックリンクに続く「stat」が呼び出されることがわかります:

$ ln -s varnish_config XXX
$ strace -s 2000 test -L XXX 2>&1 | grep XXX
execve("/usr/bin/test", ["test", "-L", "XXX"], [/* 47 vars */]) = 0
lstat("XXX", {st_mode=S_IFLNK|0777, st_size=14, ...}) = 0

$ strace -s 2000 test -L varnish_config 2>&1 | grep varnish
execve("/usr/bin/test", ["test", "-L", "varnish_config"], [/* 47 vars */]) = 0
lstat("varnish_config", {st_mode=S_IFREG|0664, st_size=1046, ...}) = 0

$ strace -s 2000 test -f XXX 2>&1 | grep XXX
execve("/usr/bin/test", ["test", "-f", "XXX"], [/* 47 vars */]) = 0
stat("XXX", {st_mode=S_IFREG|0664, st_size=1046, ...}) = 0

statのmanページから:

   stat() stats the file pointed to by path and fills in buf.

   lstat() is identical to stat(), except that if path is a symbolic link,
   then the link itself is stat-ed, not the file that it refers to.

これは、指定されたファイル名が通常のファイルまたは通常のファイル自体へのシンボリックリンクである限り、-fテストがtrueを返すことを意味します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.