回答:
でzsh
、それはただです:
mypath=$0:A
ただしrealpath()
、他のシェルの場合、とreadlink()
は標準関数(後者はシステムコール)でrealpath
ありreadlink
、標準コマンドではありませんが、システムによっては、さまざまな動作と機能セットを持つ一方または両方があります。
頻繁に、移植性のために、あなたはに頼ることができますperl
:
abs_path() {
perl -MCwd -le '
for (@ARGV) {
if ($p = Cwd::abs_path $_) {
print $p;
} else {
warn "abs_path: $_: $!\n";
$ret = 1;
}
}
exit $ret' "$@"
}
dirnameが存在する限りファイルが存在しなくても文句を言わないという点で(GNU )readlink -f
よりもGNUのように振る舞います。realpath()
readlink -e
zshでは、次のことができます。
mypath=${0:a}
または、スクリプトが存在するディレクトリを取得するには:
mydir=${0:a:h}
ソース:zshexpn(1)manページ、セクションHISTORY EXPANSION、サブセクションModifiers(または単にinfo -f zsh -n Modifiers
)。
readlink -f
はむしろになります$0:A
。
私は数年前からこれを使用しています:
# The absolute, canonical ( no ".." ) path to this script
canonical=$(cd -P -- "$(dirname -- "$0")" && printf '%s\n' "$(pwd -P)/$(basename -- "$0")")
readlink -f
は、スクリプト自体がシンボリックリンクである場合です。
zsh
、これを直接またはサブシェル(推奨)で実行すると、ホームdir(/home/ville
)で出力され/home/ville/zsh
ます。
この構文は、(で試験したいずれのBourneシェルスタイルのインタプリタに移植する必要がありbash
、ksh88
、ksh93
、zsh
、mksh
、dash
およびbusybox sh
):
mypath=$(exec 2>/dev/null;cd -- $(dirname "$0"); unset PWD; /usr/bin/pwd || /bin/pwd || pwd)
echo mypath=$mypath
このバージョンは、レガシーAT&T Bourneシェル(非POSIX)との互換性を追加します。
mypath=`dirname "$0"`
mypath=`exec 2>/dev/null;(cd -- "$mypath") && cd -- "$mypath"|| cd "$mypath"; unset PWD; /usr/bin/pwd || /bin/pwd || pwd`
echo mypath=$mypath
$PWD
するのはやり過ぎかもしれません-のように絶対電流に設定できますcd -P .
。それがボーンシェルでうまくいくとは思いませんが、最初にテストしたすべてでうまくいくはずです。とにかく私のために。
zsh
とdirname
HIR撤退迅速/彼女のコメント...しかし
絶対パス、つまりルートディレクトリからのパスを本当に意味すると仮定します。
case $0 in
/*) mypath=$0;;
*) mypath=$PWD/$0;;
esac
ちなみに、これはBourneスタイルのシェルで機能します。
すべてのシンボリックリンクが解決されたパスを意味する場合、それは別の問題です。readlink -f
Linux(一部の簡略化されたBusyBoxシステムを除く)、FreeBSD、NetBSD、OpenBSD、およびCygwinで動作しますが、OS / X、AIX、HP / UXまたはSolarisでは動作しません。がある場合readlink
、ループで呼び出すことができます:
realpath () {
[ -e "$1" ] || return
case $1 in
/*) :;;
*) set "$PWD/$1";;
esac
while [ -L "$1" ]; do
set "${1%/*}" "$(readlink "$1")"
case $2 in
/*) set "$2";;
*) if [ -z "$1" ]; then set "/$2"; else set "$(cd "$1" && pwd -P)/$2"; fi;;
esac
done
case $1 in
*/.|*/..) set "$(cd "$1" && pwd -P)";;
*/./*|*/../*) set "$(cd "${1%/*}" && pwd -P)/${1##*/}"
esac
realpath=$1
}
を持っていない場合はreadlink
、で近似できますがls -n
、これls
はファイル名に印刷できない文字が含まれていない場合にのみ機能します。
poor_mans_readlink () {
if [ -L "$1" ]; then
set -- "$1" "$(LC_ALL=C command ls -n -- "$2"; echo z)"
set -- "${2%??}"
set -- "${2#*"$1 -> "}"
fi
printf '%s\n' "$1"
}
(余分なのz
は、リンクのターゲットが改行で終わる場合です。そうしないと、コマンドの置換がrealpath
実行されなくなります。関数は、ディレクトリ名の場合は処理しません。)
ls
をマングルする実装を知っていますか?
touch Stéphane; LC_ALL=C busybox ls Stéphane | cat
→ St??phane
(名前がUTF-8の場合、latin1は単一のを提供します?
)。私は古い商用ユニックスでもそれを見たと思います。
busybox
これは何ですか?gitに よるとbusybox ls
、2011年以降、コードは変更されてbusybox ls
いません。2013年頃- 私はこのことを行いません。この1 -年頃2012 - ありません。これが理由を説明するかもしれません。busybox
Unicodeサポートを使用して構築しましたか?wcharサポートを含めますか?mkinitcpio
busybox
パッケージのビルドオプションを確認するために、試してみることをお勧めします。
必要なディレクトリへの絶対パスが必要な場合は、現在のディレクトリ(またはシェルスクリプトを実行したディレクトリ)に対する実行権限がある場合cd
。
場合は
-P
オプションが有効になっている、$PWD
環境変数はによって出力される文字列に設定されなければなりませんpwd -P
。新しいディレクトリまたはそのディレクトリの親に現在の作業ディレクトリを決定するための十分な権限がない場合、$PWD
環境変数の値は指定されません。
標準出力に書き込まれるパス名には、シンボリックリンクタイプのファイルを参照するコンポーネントは含まれません。
pwd
ユーティリティが標準出力に書き込めるパス名が複数ある場合、1つは単一の/スラッシュ文字で始まり、1つ以上の/スラッシュ文字で始まる場合は、1つの/スラッシュ文字で始まるパス名を書き込みます。パス名には、先頭の1つまたは2つの/スラッシュ文字の後に不要な/スラッシュ文字を含めることはできません。
ので、それはだcd -P
ものに、現在の作業ディレクトリを設定する必要がありpwd -P
そうでない場合は印刷する必要がありますし、そのcd -
印刷している$OLDPWD
こと、次の作品を:
mkdir ./dir
ln -s ./dir ./ln
cd ./ln ; cd . ; cd -
/home/mikeserv/test/ln
それを待つ...
cd -P . ; cd . ; cd -
/home/mikeserv/test/dir
そして、私が印刷しcd -
ているときは、印刷してい$OLDPWD
ます 絶対パスになったらすぐにcd
設定$PWD
しcd -P .
$PWD
ます/
-他の変数は必要ありません。そして実際に、私も末尾は必要ありません.
が、リセットの指定された動作がある$PWD
に$HOME
するとき、対話型シェルで cd
飾り気のないですが。ですから、開発するのは良い習慣です。
したがって、パスで上記を実行するだけでパス${0%/*}
を検証する$0
のに十分なはずです$0
が、それ自体がソフトリンクである場合は、残念ながらディレクトリに変更することはできません。
これを処理する関数は次のとおりです。
zpath() { cd -P . || return
_out() { printf "%s$_zdlm\n" "$PWD/${1##*/}"; }
_cd() { cd -P "$1" ; } >/dev/null 2>&1
while [ $# -gt 0 ] && _cd .
do if _cd "$1"
then _out
elif ! [ -L "$1" ] && [ -e "$1" ]
then _cd "${1%/*}"; _out "$1"
elif [ -L "$1" ]
then ( while set -- "${1%?/}"; _cd "${1%/*}"; [ -L "${1##*/}" ]
do set " $1" "$(_cd -; ls -nd -- "$1"; echo /)"
set -- "${2#*"$1" -> }"
done; _out "$1"
); else ( PS4=ERR:\ NO_SUCH_PATH; set -x; : "$1" )
fi; _cd -; shift; done
unset -f _out _cd; unset -v _zdlm
}
サブシェルを呼び出さずに、現在のシェルでできる限りのことを行うように努めていますが、エラーを検出するサブシェルや、ディレクトリを指していないソフトリンクがあります。POSIX互換のシェルとPOSIX互換ls
のクリーンな_function()
名前空間に依存します。後者がなくてもunset
正常に機能しますが、その場合、現在のシェル関数を上書きする場合があります。一般に、これらの依存関係はすべて、Unixマシンでかなり確実に使用できるはずです。
引数付きまたは引数なしで呼び出された場合、最初に行われるの$PWD
はその標準値にリセットされます。必要に応じて、ターゲットへのリンクを解決します。引数なしで呼び出され、それはそれについてです。しかし、それらと一緒に呼び出されると、それぞれのパスを解決して正規化し、stderr
そうでない場合はメッセージを出力します。
ほとんどの場合、現在のシェルで動作するため、任意の長さの引数リストを処理できるはずです。また、$_zdlm
変数(unset
それが通過したときにも表示される)を探し、その各引数のすぐ右側にCエスケープされた値を出力します。各引数には、常に単一の\n
ewline文字も続きます。
多くのディレクトリ変更を行いますが、正規の値に設定すること以外は、影響しませんが$PWD
、$OLDPWD
通過した時点で決してカウントすることはできません。
可能な限り早く各引数を終了しようとします。それは最初にしようとcd
し$1
ます。可能であれば、引数の正規のパスをに出力しますstdout
。それができない場合、$1
存在することを確認し、ソフトリンクではありません。trueの場合、印刷します。
このように$1
して、ディレクトリを指し示していないシンボリックリンクでない限り、シェルがアドレス指定するファイルタイプ引数を処理します。その場合while
、サブシェルでループを呼び出します。
ls
リンクを読み取るために呼び出します。参照パスを確実に処理するために、最初に現在のディレクトリを初期値に変更する必要があります。そのため、コマンド置換サブシェルで関数は次のことを行います。
cd -...ls...echo /
ls
リンクの名前と文字列を完全に含めるために必要な限り、出力の左側から削除します->
。私は、最初のを避けるためにしようとしたもののでこれを行うshift
と$IFS
、これは私が理解できるように近いとして最も信頼性の高い方法であるが判明しました。これは、Gillesのpoor_mans_readlinkと同じことであり、よくできています。
返されたファイル名ls
が間違いなくソフトリンクでなくなるまで、このプロセスをループで繰り返します。その時点で、以前と同様にそのパスを正規化してcd
から印刷します。
使用例:
zpath \
/tmp/script \ #symlink to $HOME/test/dir/script.sh
ln \ #symlink to ./dir/
ln/nl \ #symlink to ../..
/dev/fd/0 \ #currently a here-document like : dash <<\HD
/dev/fd/1 \ #(zlink) | dash
file \ #regular file
doesntexist \ #doesnt exist
/dev/disk/by-path/pci-0000:00:16.2-usb-0:3:1.0-scsi-0:0:0:0 \
/dev/./././././././null \
. ..
/home/mikeserv/test/dir/script.sh
/home/mikeserv/test/dir/
/home/mikeserv/test/
/tmp/zshtpKRVx (deleted)
/proc/17420/fd/pipe:[1782312]
/home/mikeserv/test/file
ERR: NO_SUCH_PATH: doesntexist
/dev/sdd
/dev/null
/home/mikeserv/test/
/home/mikeserv/
または多分...
ls
dir/ file file? folder/ link@ ln@ script* script3@ script4@
zdlm=\\0 zpath * | cat -A
/home/mikeserv/test/dir/^@$
/home/mikeserv/test/file^@$
/home/mikeserv/test/file$
^@$
/home/mikeserv/test/folder/^@$
/home/mikeserv/test/file$ #'link' -> 'file\n'
^@$
/home/mikeserv/test/dir/^@$ #'ln' -> './dir'
/home/mikeserv/test/script^@$
/home/mikeserv/test/dir/script.sh^@$ #'script3' -> './dir/script.sh'
/home/mikeserv/test/dir/script.sh^@$ #'script4' -> '/tmp/script' -> ...
アルゴリズムの再定義を防ぐために利用可能なPythonがある場合、同情的なワンライナーはどうですか?
function readlink { python -c "import os.path; print os.path.realpath('$1')"; }