相対パスを指定して絶対パスを取得するコマンドはありますか?
たとえば、$ lineに各ファイルの絶対パスをdir ./etc/
に含めたい
find ./ -type f | while read line; do
echo $line
done
つかいます:
find $(pwd)/ -type f
すべてのファイルを取得するか、
echo $(pwd)/$line
フルパスを表示する(相対パスが重要な場合)
realpath
を試してください。
~ $ Sudo apt-get install realpath # may already be installed
~ $ realpath .bashrc
/home/username/.bashrc
シンボリックリンクの拡張を回避するには、realpath -s
を使用します。
答えは、「 ファイルへの絶対パスを出力するbash/fishコマンド 」から来ています。
Coreutilsパッケージをインストールしている場合は、通常、readlink -f relative_file_name
を使用して絶対パッケージを取得できます(すべてのシンボリックリンクが解決されます)
#! /bin/sh
echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"
UPD説明
"$1"
dirname "$1"
cd "$(dirname "$1")
し、pwd
Shellコマンドを実行して、その絶対パスを取得します。$(basename "$1")
echo
itそれが価値があるものとして、私は選ばれた答えに投票しましたが、解決策を共有したいと思いました。欠点は、Linuxのみだということです。スタックオーバーフローが発生する前に、OSXで同等のものを見つけるのに5分ほど費やしました。きっとそこにあると思います。
Linuxでは、readlink -e
をdirname
と組み合わせて使用できます。
$(dirname $(readlink -e ../../../../etc/passwd))
利回り
/etc/
そして、dirname
の姉妹、basename
を使用してファイル名を取得します
$(basename ../../../../../passwd)
利回り
passwd
全部まとめて..
F=../../../../../etc/passwd
echo "$(dirname $(readlink -e $F))/$(basename $F)"
利回り
/etc/passwd
ディレクトリをターゲットにしている場合は安全です。basename
は何も返さず、最終出力にダブルスラッシュが表示されます。
私はこれが最もポータブルだと思う:
abspath() {
cd "$(dirname "$1")"
printf "%s/%s\n" "$(pwd)" "$(basename "$1")"
cd "$OLDPWD"
}
ただし、パスが存在しない場合は失敗します。
realpath
がおそらく最適です
しかし...
最初の質問は最初に非常に混乱しており、前述のように質問との関連性が低い例がありました。
選択された回答は、実際にはタイトルの質問ではなく、与えられた例に回答します。最初のコマンドはその答えであり(本当にそうなのでしょうか?私は疑います)、「/」なしでも同様に実行できます。そして、2番目のコマンドが何をしているのかがわかりません。
いくつかの問題が混在しています:
相対パス名を絶対パス名に変更します。それが何であれ、おそらく何もしません。 (通常、touch foo/bar
などのコマンドを発行する場合、ファイルが実際に作成される前に、パス名foo/bar
が存在し、場合によっては計算で使用される必要があります。)
同じファイル(または潜在的なファイル)を示すいくつかの絶対パス名が存在する可能性があります。特にパス上のシンボリックリンク(シンボリックリンク)が原因である可能性があります。そのようなシンボリックリンクを明示的に解決したい場合としない場合があります。
非シンボリックファイルまたは名前へのシンボリックリンクのチェーンの最後に到達します。これは、その実行方法に応じて、絶対パス名を生成する場合としない場合があります。そして、それを絶対パス名に解決したい場合もしたくない場合もあります。
オプションなしのコマンドreadlink foo
は、引数foo
がシンボリックリンクであり、その答えがそのシンボリックリンクの値である場合にのみ答えを返します。他のリンクはたどられません。答えは相対パスの場合があります。symlink引数の値は何でもかまいません。
ただし、readlink
には、すべてのファイルに対して機能するオプション(-f -eまたは-m)があり、実際に引数で示されるファイルに1つの絶対パス名(シンボリックリンクがないもの)を指定します。
これは、シンボリックリンクではないものに対しては正常に機能しますが、パス上の中間のシンボリックリンクを解決せずに絶対パス名を使用したい場合があります。これはコマンドrealpath -s foo
によって行われます
シンボリックリンク引数の場合、readlink
とそのオプションは、引数への絶対パス上のすべてのシンボリックリンクを再び解決しますが、引数値に従うことで遭遇する可能性のあるすべてのシンボリックリンクも含まれます。引数のシンボリックリンク自体への絶対パスが必要な場合は、リンク先を指定するのではなく、それを望まないかもしれません。繰り返しますが、foo
がシンボリックリンクの場合、realpath -s foo
は、引数として指定されたものを含め、シンボリックリンクを解決せずに絶対パスを取得します。
-s
オプションを指定しない場合、realpath
は、リンクの値を読み取るだけでなく、他のいくつかのことを除いて、readlink
とほとんど同じです。 readlink
にオプションがある理由は明らかではありませんが、realpath
で明らかに望ましくない冗長性が生じます。
Webを探索することは、システム間でいくつかのバリエーションがあるかもしれないことを除いて、それ以上のことは言いません。
結論:realpath
は、少なくともここで要求されている使用に対して、最も柔軟性があり、使用するのに最適なコマンドです。
オイゲンの答えは私にはうまくいきませんでしたが、これはうまくいきました:
absolute="$(cd $(dirname \"$file\"); pwd)/$(basename \"$file\")"
補足説明として、現在の作業ディレクトリは影響を受けません。
私のお気に入りの解決策は、他のユーティリティ(coreutilsパッケージ)の存在を暗示していないため、@ EugenKonkovによる the one でした。
しかし、相対パス「。」では失敗しました。そして「..」なので、これらの特殊なケースを処理するわずかに改善されたバージョンがあります。
ただし、ユーザーが相対パスの親ディレクトリへのcd
へのアクセス許可を持っていない場合でも失敗します。
#! /bin/sh
# Takes a path argument and returns it as an absolute path.
# No-op if the path is already absolute.
function to-abs-path {
local target="$1"
if [ "$target" == "." ]; then
echo "$(pwd)"
Elif [ "$target" == ".." ]; then
echo "$(dirname "$(pwd)")"
else
echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"
fi
}
realpathが存在せず、readlinkが絶対パスを印刷できないMac OS Xでbashを使用している場合、独自のバージョンをコーディングして印刷することもできます。これが私の実装です。
(純粋なbash)
abspath(){
local thePath
if [[ ! "$1" =~ ^/ ]];then
thePath="$PWD/$1"
else
thePath="$1"
fi
echo "$thePath"|(
IFS=/
read -a parr
declare -a outp
for i in "${parr[@]}";do
case "$i" in
''|.) continue ;;
..)
len=${#outp[@]}
if ((len==0));then
continue
else
unset outp[$((len-1))]
fi
;;
*)
len=${#outp[@]}
outp[$len]="$i"
;;
esac
done
echo /"${outp[*]}"
)
}
(use gawk)
abspath_gawk() {
if [[ -n "$1" ]];then
echo $1|gawk '{
if(substr($0,1,1) != "/"){
path = ENVIRON["PWD"]"/"$0
} else path = $0
split(path, a, "/")
n = asorti(a, b,"@ind_num_asc")
for(i in a){
if(a[i]=="" || a[i]=="."){
delete a[i]
}
}
n = asorti(a, b, "@ind_num_asc")
m = 0
while(m!=n){
m = n
for(i=1;i<=n;i++){
if(a[b[i]]==".."){
if(b[i-1] in a){
delete a[b[i-1]]
delete a[b[i]]
n = asorti(a, b, "@ind_num_asc")
break
} else exit 1
}
}
}
n = asorti(a, b, "@ind_num_asc")
if(n==0){
printf "/"
} else {
for(i=1;i<=n;i++){
printf "/"a[b[i]]
}
}
}'
fi
}
(純粋なbsd awk)
#!/usr/bin/env awk -f
function abspath(path, i,j,n,a,b,back,out){
if(substr(path,1,1) != "/"){
path = ENVIRON["PWD"]"/"path
}
split(path, a, "/")
n = length(a)
for(i=1;i<=n;i++){
if(a[i]==""||a[i]=="."){
continue
}
a[++j]=a[i]
}
for(i=j+1;i<=n;i++){
delete a[i]
}
j=0
for(i=length(a);i>=1;i--){
if(back==0){
if(a[i]==".."){
back++
continue
} else {
b[++j]=a[i]
}
} else {
if(a[i]==".."){
back++
continue
} else {
back--
continue
}
}
}
if(length(b)==0){
return "/"
} else {
for(i=length(b);i>=1;i--){
out=out"/"b[i]
}
return out
}
}
BEGIN{
if(ARGC>1){
for(k=1;k<ARGC;k++){
print abspath(ARGV[k])
}
exit
}
}
{
print abspath($0)
}
例:
$ abspath I/am/.//..//the/./god/../of///.././war
/Users/leon/I/the/war
find
の場合、検索するための絶対パスを指定するのがおそらく最も簡単です。たとえば:
find /etc
find `pwd`/subdir_of_current_dir/ -type f
最良の解決策であるimhoは、ここに投稿されたものです https://stackoverflow.com/a/3373298/9724628 。
動作するにはpythonが必要ですが、Edgeのケースのすべてまたはほとんどをカバーし、非常に移植性の高いソリューションであるようです。
python -c "import os,sys; print os.path.realpath(sys.argv[1])" path/to/file
python -c "import os,sys; print os.path.abspath(sys.argv[1])" path/to/file
echo "mydir/doc/ mydir/usoe ./mydir/usm" | awk '{ split($0,array," "); for(i in array){ system("cd "array[i]" && echo $PWD") } }'
@ ernest-aの答えに似ていますが、$OLDPWD
に影響を与えたり、新しい関数を定義したりせずに、サブシェル(cd <path>; pwd)
を起動できます。
$ pwd
/etc/Apache2
$ cd ../cups
$ cd -
/etc/Apache2
$ (cd ~/..; pwd)
/Users
$ cd -
/etc/cups
相対パスがディレクトリパスの場合は、私のものを試してください。
absPath=$(pushd ../SOME_RELATIVE_PATH_TO_Directory > /dev/null && pwd && popd > /dev/null)
echo $absPath
find $PWD
または(bashで)find ~+
を除き、彼らが言ったことはもう少し便利です。
これは、他のすべてからの連鎖ソリューションです。たとえば、realpath
がインストールされていないか、エラーコードで終了したために失敗した場合、パスが正しくなるまで次のソリューションが試行されます。
#!/bin/bash
function getabsolutepath() {
local target;
local changedir;
local basedir;
local firstattempt;
target="${1}";
if [ "$target" == "." ];
then
printf "%s" "$(pwd)";
Elif [ "$target" == ".." ];
then
printf "%s" "$(dirname "$(pwd)")";
else
changedir="$(dirname "${target}")" && basedir="$(basename "${target}")" && firstattempt="$(cd "${changedir}" && pwd)" && printf "%s/%s" "${firstattempt}" "${basedir}" && return 0;
firstattempt="$(readlink -f "${target}")" && printf "%s" "${firstattempt}" && return 0;
firstattempt="$(realpath "${target}")" && printf "%s" "${firstattempt}" && return 0;
# If everything fails... TRHOW PYTHON ON IT!!!
local fullpath;
local pythoninterpreter;
local pythonexecutables;
local pythonlocations;
pythoninterpreter="python";
declare -a pythonlocations=("/usr/bin" "/bin");
declare -a pythonexecutables=("python" "python2" "python3");
for path in "${pythonlocations[@]}";
do
for executable in "${pythonexecutables[@]}";
do
fullpath="${path}/${executable}";
if [[ -f "${fullpath}" ]];
then
# printf "Found ${fullpath}\\n";
pythoninterpreter="${fullpath}";
break;
fi;
done;
if [[ "${pythoninterpreter}" != "python" ]];
then
# printf "Breaking... ${pythoninterpreter}\\n"
break;
fi;
done;
firstattempt="$(${pythoninterpreter} -c "import os, sys; print( os.path.abspath( sys.argv[1] ) );" "${target}")" && printf "%s" "${firstattempt}" && return 0;
# printf "Error: Could not determine the absolute path!\\n";
return 1;
fi
}
printf "\\nResults:\\n%s\\nExit: %s\\n" "$(getabsolutepath "./asdfasdf/ asdfasdf")" "${?}"
相対パスを含む変数を絶対パスに変換したい場合、これは動作します:
dir=`cd "$dir"`
ここでサブシェルで実行されるため、「cd」は作業ディレクトリを変更せずにエコーします。