PATH検索にはシンボリックリンクが含まれますか?


9

POSIXシェル標準はこのサイトで述べています

http://pubs.opengroup.org/onlinepubs/9699919799/

シェルPATHが実行可能ファイルを探すためにどのように使用するかについて:

「リストは最初から最後まで検索され、指定された名前と適切な実行権限を持つ実行可能ファイルが見つかるまで、各プレフィックスにファイル名が適用されます。」

まあ、これはこれが実際のPOSIX実装で動作するように見える方法ではありません:

man which 言う:

「現在の環境で実行されるファイル(またはリンク)のパス名を返します。引数が厳密にPOSIX準拠のシェルでコマンドとして指定されている場合、これは、PATHを検索して、引数。シンボリックリンクには従いません。」

OK、この状況を見てみましょう:

$ pwd /home/mark

$ echo $PATH /home/mark/bin:...

$ ls -l bin/foobar
lrwxrwxrwx 1 mark mark 18 Dec 12 22:51 bin/foobar -> /home/mark/foobar1
$ touch foobar1
$ which foobar
$ chmod a+x foobar1
$ which foobar
/home/mark/bin/foobar

OK、PATH正しい名前のシンボリックリンクがここにあり、ls実行可能であると報告されています。

which それはまったく見ていませんが、それが指しているものにのみ興味があります。

両方があるという事実にもかかわらず、それman whichを明示的にはシンボリックリンクをたどりません(実際、我々はので、それは、ない見ることを言ってwhich foobar印刷されないfoobar1)、また、POSIXシェルのドキュメントは、上記引用されていること、決してで次のシンボリックリンクを言及PATHするアルゴリズム。

では、which既存のシェルは間違っていますか、それともドキュメントが理解できていませんか?

明確にするために:

私は知っており、既存の行動を説明できます。私の質問は「これはどのように機能するのですか?」ではありません。私が知っています。

私の質問はドキュメンテーションについてです。引用したドキュメンテーションをフォローする際の私の間違いはどこにありますか。または、ドキュメントが間違っていますか?

動機:なぜ気にするのか?

まあ、私は実装者です。実装者が異なれば、要件も異なります。私にとっての要件は、現在のPOSIX標準の言葉を正確に遵守する必要があることです(正確には、標準自体が多少バグがあるため、より正確に言えば、可能な限り最高です)。神の言葉のように。

現在、標準的な表現はかなり明確です-以下のシンボリックリンクについては言及されていませんが、他の多くの場所では、それを行う必要がある場所について言及されています。したがって、この場合はしないでください。

ただし、念のため念のため、方法dashbash動作を常に確認します。もちろん、dashPOSIXとして請求されていますが、POSIXに準拠した小さなバグがたくさんありますが、ここでも少し問題があります。 bash、私はまだPOSIXのバグを見つけていませんが、bashは実際にはPOSIXではありません。それだけではありません。

だからあなたはそれを持っています。それが私が気にする理由です。


理解できません:ファイルのシンボリックリンクをたどりません。$PATHシンボリックリンクを含めることができます。お試しくださいwhich sh
Ipor Sircer 2017

わかりましたが、私の場合$PATH、シンボリックリンクはありません。
user322908 2017

ほとんどすべての状況で、シンボリックリンクは透過的に追跡されます。それらがそうでない場合は通常明示的に述べられており(例えばのようなシステムコールlstat(2))、それらに従うことは通常述べられていません。たとえば、の説明ではopen(2)、の動作について説明するときにシンボリックリンクについてのみ言及していますO_CREAT | O_EXCL。ターゲットファイルが開かれることを示す必要はありません。
Barmar 2017

回答:


10

シンボリックリンク自体の権限は関係ありません。あなたが試みた場合、それらを変更することさえできませんでした。

重要なのは、基になるファイルの権限です。

PATHのディレクトリに実行可能ファイルへのシンボリックリンクを含めることは問題ありません。実際、PATH内の多くの実行可能ファイルはシンボリックリンクである可能性があります。たとえば、debian / ubuntuのようなシステムでは:

$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Jan 23  2017 /bin/sh -> dash

ドキュメンテーション

からman chmod

chmodがシンボリックリンクのアクセス許可を変更することはありません。chmodシステムコールは、権限を変更できません。シンボリックリンクのアクセス許可は決して使用されないため、これは問題ではありません ただし、コマンド行にリストされているシンボリックリンクごとに、chmodはポイントされたファイルのアクセス許可を変更します。対照的に、chmodは再帰的なディレクトリトラバーサル中に検出されたシンボリックリンクを無視します。[エンファシスが追加されました。]

シェルには、-xファイルが実行可能かどうかを判断するためのテストがあります。それを試してみましょう:

$ ls -l
total 0
lrwxrwxrwx 1 john1024 john1024 7 Dec 12 23:36 foo -> foobar1
-rw-rw---- 1 john1024 john1024 0 Dec 12 23:36 foobar1
$ [ -x foo ] && echo foo is executable
$ chmod +x foobar1
$ [ -x foo ] && echo foo is executable
foo is executable

したがって、で見つけたようにwhich、基礎となるファイルが実行可能でない限り、シェルはソフトリンク実行可能ファイルを考慮しません。

どのように機能するか

Debianシステムでwhichは、シェルスクリプトです。コードの関連セクションは次のとおりです。

 case $PROGRAM in
  */*)
   if [ -f "$PROGRAM" ] && [ -x "$PROGRAM" ]; then
    puts "$PROGRAM"
    RET=0
   fi
   ;;
  *)
   for ELEMENT in $PATH; do
    if [ -z "$ELEMENT" ]; then
     ELEMENT=.
    fi
    if [ -f "$ELEMENT/$PROGRAM" ] && [ -x "$ELEMENT/$PROGRAM" ]; then
     puts "$ELEMENT/$PROGRAM"
     RET=0
     [ "$ALLMATCHES" -eq 1 ] || break
    fi
   done
   ;;
 esac

ご覧のとおり、-xテストを使用して、ファイルが実行可能かどうかを判断します。

POSIXでは、-xテストを次のように指定しています。

-x pathname ファイルの読み取り、書き込み、作成で定義され
ているように、ファイルを実行する(またはディレクトリの場合は検索する)許可が与えられるファイルの既存のディレクトリエントリにpathnameが解決される場合はtrue。パス名を解決できない場合、またはパス名がファイルの実行(または検索)権限が付与されないファイルの既存のディレクトリエントリに解決される場合はfalse。[エンファシスが追加されました。]

したがって、POSIXはパス名の解決先をチェックします。つまり、シンボリックリンクを受け入れます。

POSIX exec関数

POSIX exec関数は、シンボリックリンクをたどります。POSIX仕様では、シンボリックリンクが循環しているか深すぎる場合に報告される可能性があるエラー条件を指定するために、次のように詳しく説明しています。

[ELOOP]
パスまたはファイル引数の解決中に遭遇したシンボリックリンクにループが存在します。

[ELOOP]
パスまたはファイル引数の解決中に{SYMLOOP_MAX}を超えるシンボリックリンクが検出されました。
[ENAMETOOLONG]
パス引数の解決でシンボリックリンクが検出された結果、置換されたパス名文字列の長さが{PATH_MAX}を超えました。


私はあなたがあなたの答えに書いたすべてを知っています。私は物事がどのように「働く」かを知っています。それは私の質問ではありません。私の質問はドキュメントについてです。ドキュメントを理解していない場所を教えてください。または、ドキュメントが正しくないことを教えてください。
user322908 2017

@ user322908ほとんどのシステムでwhichは、シェルスクリプトです。したがって、おそらく-x私が示したテストを使用しているだけです。POSIXによると-x、ファイルが実行可能ファイルに「解決」されるかどうかをテストします。別のものが表示されている場合、どこを探していますか?
John1024 2017

ありがとうございました。大変なご苦労で申し訳ありません...私の質問は99%の質問とは異なるため、自分が何を求めているのか理解するのが難しいことに気づきました。繰り返しますが、私は「仕組み」whichや、それが-x何か他のものであるかどうかには興味がありません。引用したドキュメントを正しくフォローしていない場所を知りたいです。
user322908 2017

4
@ user322908 POSIX exec関数はシンボリックリンクに従います。これにより、シンボリックリンクされたファイルがPOSIXで実行可能であることが明確になります。
John1024

2
「パス名を正規化しない」というUbuntu 17.10 man whichもチェックしました。それはリンクをたどらないという意味ではありません。これは、ご存じのとおり、名前を「正規化」しないことを意味します。
John1024

3

この場合、最終パスを正規化せずにシンボリックリンクを透過的にたどります。言い換えれば、which/home/mark/binシンボリックリンクであるかどうかを気にしません。ファイル/home/mark/bin/foobarが存在するかどうかが重要です。それは必要としないパスに沿って手動で平らにシンボリックリンクに- OSは、自分自身でそれだけで罰金を行うことができます。

実際、のwhichファイル情報について尋ねられる/home/mark/bin/foobarと、OS /home/mark/binはシンボリックリンクであることを認識し、それに従ってfoobar、ターゲットディレクトリで正常に検出されます。

プログラムがファイルを使用するopen(…, O_NOFOLLOW)fstatat(…, AT_SYMLINK_NOFOLLOW)、ファイルにアクセスしない限り、これがデフォルトの動作です。

[コメントが統合されました]

シェルユーティリティはケースバイケースでそれを行うと言っていますが、カーネルのsyscallと同じではありません。「nofollow」フラグが指定されていない限り、すべてのファイル関連の呼び出しデフォルトでシンボリックリンクに従います。(lstatでも、最後のものを除くすべてのパスコンポーネントのシンボリックリンクをたどります。)

仕様でシンボリックリンクの処理方法が明示されていない場合、デフォルトの動作が使用されることを意味します。つまり、パスアルゴリズムに従うシェルは、シンボリックリンクを手動で解決すること、OSから同じように明示的にオプトアウトすることもありませ。(各$ PATHコンポーネントを実行可能ファイル名と連結するだけです。)

which(1)マニュアルページにシンボリックリンクをたどらないと書かれている場合、それはいくつかのことを意味する可能性がありますが、GNU coreutilsバージョンでは次のように述べています。

どちらかにシンボリックリンクのあるパスが含まれている場合、2つの同等のディレクトリが異なると見なされます。

これは範囲がはるかに狭くなります。つまり、重複を削除するためにすべてのパスwhich手動で正規化しないことを意味しますが、OSが一般的に従うシンボリックリンクをツールがオプトアウトすることを意味しません。例えば、場合は、/binへのシンボリックリンクで/usr/bin実行し、which -a sh返されます両方を /bin/shして/usr/bin/sh


はい、ありがとうございます。これはすべて知っています。私の質問は、物事がどのように「機能する」かではありません。私はそれらがどのように機能するかを知っています。それは私の趣旨ではありません。私のポイントはドキュメントについてです。どこでドキュメントを誤ってフォローしていますか。または、ドキュメントが正しくありません。
user322908 2017

2
ドキュメントを正しく理解していない–次のシンボリックリンクが記載されていない場合、手動でシンボリックリンク解決しませんが、通常のOSの動作は引き続き適用されます。GNUのwhichマニュアルページには、「2つの同等のディレクトリの1つにシンボリックリンクのパスが含まれている場合、どちらが異なると見なされるか」とは異なって記載されています。
user1686 2017

わかりました、ありがとうございます。私は理解しようとしています...しかし...私の首の痛みは許してください。「通常のOSの動作」は、常に暗黙的にシンボリックリンクをたどることではありません。そうでないユーティリティはたくさんあります。ケースバイケースです。
user322908 2017

1
AT_SYMLINK_NOFOLLOWなどを指定しない限り、すべてのカーネル呼び出し– chdir、open、chmod、execve ... –は、パスと末尾の両方でシンボリックリンクをたどります。(lstatは、末尾のシンボリックリンクを逆参照しない唯一の1つですが、残りのパスについてもそうです。)したがって、デフォルトの動作はシンボリックリンクをたどることです。たとえば、シェルがexecve("/home/mark/bin/foobar", …)それを呼び出すと、すべてのシンボリックリンクが追跡されます。
user1686 2017

OK私はexecve議論を買っていると思います、実際、私の実装ではexecl()、それは同じことです。これを回答に含めていただければ、承諾します。
user322908 2017

1

シェルは、パス名解決の規則に従うという点で、そのドキュメントに準拠しています。 whichそのドキュメントに準拠しています。2つは少し異なることを行います。

の出力whichは、リンクのファイル名とパスであり、シンボリックリンクが指すパスではありません。これはマニュアルページで詳しく説明されています。

コマンドが実行されると、同じ 4.13節の「パス名の解決」に従ってリンクが「フォロー」されます。ファイルの実行に関連する句は次のとおりです。

他のすべての場合、システムは残りのパス名があれば、その前にシンボリックリンクの内容を付けます。ただし、シンボリックリンクの内容が空の文字列の場合、いずれかのパス名解決は失敗し、[ENOENT ]エラーとユーティリティが同等の診断メッセージを書き込んでいるか、シンボリックリンクを含むディレクトリのパス名がシンボリックリンクの内容の代わりに使用されます。シンボリックリンクの内容が文字のみで構成されている場合、残りのパス名のすべての先行文字は、結果の結合パス名から省略され、シンボリックリンクの内容の先行文字のみが残ります。接頭辞が付けられる場合、結合された長さが{PATH_MAX}を超え、実装はこれをエラーと見なし、パス名の解決は、[ENAMETOOLONG]エラーを報告する関数と同等の診断メッセージを書き込むユーティリティで失敗します。それ以外の場合、解決されたパス名は、作成されたばかりのパス名の解決になります。結果のパス名がで始まらない場合、パス名の最初のファイル名の先行は、シンボリックリンクを含むディレクトリと見なされます。

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