readlink/realpath が利用できない場合 POSIX シェルで相対パスを解決するにはどうすればよいですか?

readlink/realpath が利用できない場合 POSIX シェルで相対パスを解決するにはどうすればよいですか?

readlinkユーティリティが利用できない場合は、相対realpathパスを確認するためにPOSIXシェルスクリプトで何を使用できますか(最近はほとんどがGNU coreutilsで使用されていると思いますか?)

一つあるrealpathしかし、Cは機能します。それではおそらく別のものかもしれません。便利密かに使用しますか?

答え1

一つあるrealpathしかし、Cは機能します。それではおそらく別のものかもしれません。便利密かに使用しますか?

realpath私の頭では、これらのユーティリティのどれも仕様でこの機能を参照しているかどうかわかりません。

私が知っているすべてはテストディレクトリエントリの場合パス名は既存のディレクトリエントリで解決されます。1+x。

Peepでの実装ダッシュ(git.kernel.org)、それを使用lstat64/stat64

これはディレクトリに十分です(テスト-Dパス名)到着CDその中に入り、解決されたパス名を返します。パスワード

~のためCDCDパス設定されていないか空白でなければならず、²オペランドはハイフンマイナス記号ではありません。「-」

([ -d "$1" ] && [ '-' != "$1" ] && CDPATH= cd -P -- "$1" && pwd -P)

例:ディレクトリの絶対パス、フルパス、実際のパス名を返します。ディレクトリで解決されていない場合はnullを返します。

パス名からハイフンマイナス記号( "-")を除外するのに問題がある場合、代替策はオペランドを "./-"に設定することです。

1参照テスト²参照CDステップ5の手順、参照。cd "-"オペランド


読んでみるとすでに知っています。ディレクトリ名そして基本名、そしておそらくどのようにシンボリックリンクが壊れているか存在しないことを確認してください。 Unix & Linuxそうでない場合は、その回答の文脈を確認して興味があるかどうかを確認してください。」テスト区別などの使い方テスト -d パス名1. 終了ステータス

答え2

質問を投稿した後、次の解決策を思い出しました。

#!/bin/sh
realpath() (
    file=
    path=$1
    [ -d "$path" ] || {
        file=/$(basename -- "$path")
        path=$(dirname -- "$path")
    }
    {
        path=$(cd -- "$path" && pwd)$file
    } || exit $?
    printf %s\\n "/${path#"${path%%[!/]*}"}"
)

警告:どうやらこれまでテストできませんでした!常にフィードバックを求めてください。もしご覧になった方は、コメントを残してください。

また、他の人も以前に同じアイデアを持っていて、特に極端なケースと広範なテストの後でよりよく解決したと確信しています。ご存知の方はリンクを投稿してください。

上記のシェル機能はrealpathGNU coreutilsを置き換えますrealpath -s --https://www.gnu.org/software/coreutils/manual/html_node/realpath-inplication.html。これはシンボリックリンクが解決されなかったことを意味します。 (相対パス解決にのみ興味がある場合でも、これは必要ありません。)

  • #!/bin/sh
    

    ShebangをPOSIXシェルとして使用します。

  • realpath() (
    

    realpath() (...)代わりにサブシェルで関数を実行しても、realpath() {...}存在する可能性のあるfile変数は上書きされませんpath。 (POSIXシェルはローカル変数をサポートしていません。)

  • file=
    path=$1
    

    変数を定義します。最初に、引数によって提供されるパスが既存の$1ディレクトリであると仮定します。 (パスの最後のコンポーネントが削除しようとしているパスの反対側で.ある場合もあるため、これは重要です。)..

  • [ -d "$path" ] || {
        file=/$(basename -- "$path")
        path=$(dirname -- "$path")
    }
    

    関数引数が以前に想定したように既存のディレクトリへのパスではない場合は、$pathQuote fromを調整する必要がありますman realpath

    解決された絶対ファイル名を印刷します。最後のコンポーネントを除いて、すべて存在する必要があります。

    $fileしたがって、(「最後のコンポーネント」)が実際に既存のファイルであるか、存在しないファイルまたはフォルダであるかは重要ではありません。$path今すぐ削除し、最終的に再添付します。

  • {
        path=$(cd -- "$path" && pwd)$file
    

    ここで「トリック」が発生します。相対パスを解決するには、そのパスcdを解析してpwd最終ディレクトリを印刷するために使用します。この新しいパスは$path2.6.3 コマンドの置換サブシェルで実行します。$file最後に添付されます。

  • } || exit $?
    

    {...}この行は、前の行の変数割り当てを囲むコードブロックの理由です。ユーザーが間違ったパスを提供している場合(たとえば、最後のコンポーネントのみが存在しない場合)、cd(コマンドオーバーライド内で)失敗し、stderrにエラーメッセージを印刷する必要があります(たとえば、「...」とCDできません。 ")。エラーコード> 0で終了します。これはコマンド置換サブシェルのエラーコードでもあります。このエラーコードにアクセスするには、$?変数の割り当てがラップされます{...}。したがって、{...}ブロックが失敗した場合、関数は終了し、ゼロ以外の同じエラーコードを伝播します。

  • printf %s\\n "/${path#"${path%%[!/]*}"}"
    

    //または存在しない/aなどの極端なケースのため、結果はまたはaです。だから////a2.6.2 パラメータ拡張$path最終出力に単一のスラッシュを追加する前に、すべての先行スラッシュを削除するために使用されます。

私が実行したいくつかのテストは次のとおりです。

for path in / // /// . .. "$HOME/." "$HOME/.." "*" --help /tmp /notexisting
do
    if [ "$(realpath "$path")" != "$(/usr/bin/realpath -s -- "$path")" ]
    then
        printf %s\\n "$path"
    fi
done

関連情報