相対パスを指定して絶対パスを取得するコマンドはありますか?
たとえば、$ lineにdir内の各ファイルの絶対パスを含めたい ./etc/
find ./ -type f | while read line; do
echo $line
done
相対パスを指定して絶対パスを取得するコマンドはありますか?
たとえば、$ lineにdir内の各ファイルの絶対パスを含めたい ./etc/
find ./ -type f | while read line; do
echo $line
done
回答:
使用する:
find "$(pwd)"/ -type f
すべてのファイルを取得するか
echo "$(pwd)/$line"
絶対パスを表示する(相対パスが重要な場合)
$(pwd)
代わりに使用する理由$PWD
?(はい、私pwd
は組み込みであることを知っています)
お試しくださいrealpath
。
~ $ sudo apt-get install realpath # may already be installed
~ $ realpath .bashrc
/home/username/.bashrc
シンボリックリンクの拡張を回避するには、を使用しますrealpath -s
。
realpath
Mac(OS X 10.11 "El Capitan")では利用できないようです。:-(
realpath
CentOS 6でも利用できないようです
brew install coreutils
が組み込まれますrealpath
realpath
すでに存在しています。個別にインストールする必要はありませんでした。
realpath
Git for Windowsで利用可能です(少なくとも私にとっては)。
coreutilsパッケージがインストールされている場合、通常readlink -f relative_file_name
は絶対パッケージを取得するために使用できます(すべてのシンボリックリンクが解決されています)
brew install coreutils
。:しかし、実行可能ファイルはAGによって付加されるgreadlink -f relative_file_name
#! /bin/sh
echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"
UPDいくつかの説明
"$1"
dirname "$1"
cd "$(dirname "$1")
、この相対ディレクトリに移動し、pwd
シェルコマンドを実行して絶対パスを取得します$(basename "$1")
echo
にrealpath
またはreadlink -f
do と同等ではありません。たとえば、最後のコンポーネントがシンボリックリンクであるパスでは機能しません。
-P
にオプションをpwd
コマンド:echo "$(cd "$(dirname "$1")"; pwd -P)/$(basename "$1")"
価値のあるものについて、私は選ばれた答えに投票しましたが、解決策を共有したいと思いました。欠点は、それが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
何も返さず、最終出力に2つのスラッシュが含まれるだけです。
dirname
、readlink
とbasename
。これにより、ターゲットではなく、シンボリックリンクの絶対パスを取得することができました。
/home/GKFX
とtouch newfile
入力した場合、Enterキーを押す前に、「create / home / GKFX / newfile」を意味することを理解できます。これは、まだ存在しないファイルへの絶対パスです。
これが最もポータブルだと思います:
abspath() {
cd "$(dirname "$1")"
printf "%s/%s\n" "$(pwd)" "$(basename "$1")"
cd "$OLDPWD"
}
パスが存在しない場合は失敗します。
dirname
、GNUコアユーティリティであり、私が信じているすべてのunixenに共通するわけではありません。
dirname
はPOSIX標準ユーティリティです。ここを参照してください:pubs.opengroup.org/onlinepubs/9699919799/utilities/dirname.html
${1##*/}
1日間使用するバージョンを修正しようとしていましたが、そのゴミを置き換えたのでbasename "$1"
、最後に/で終わるパスを適切に処理しているようです。
../..
realpath
おそらく最高です
だが ...
最初の質問は、最初は非常に混乱していましたが、前述のように、質問との関連性が低い例がありました。
選択された回答は実際には与えられた例に回答し、タイトルの質問にはまったく回答しません。最初のコマンドはその答えです(それは本当ですか?疑問です)。 '/'がなくても同じことができます。そして、2番目のコマンドが何をしているのかわかりません。
いくつかの問題が混在しています:
相対パス名を絶対パス名に変更します。それが何を示していても、おそらく何もしません。(通常、などのコマンドを発行する場合、ファイルが実際に作成される前touch foo/bar
に、パス名foo/bar
が存在し、計算で使用される可能性があります。)
特にパス上のシンボリックリンク(シンボリックリンク)が原因で、同じファイル(または潜在的なファイル)を示すいくつかの絶対パス名が存在する可能性がありますが、他の理由(デバイスが読み取り専用として2倍にマウントされている可能性があります)。そのようなシンボリックリンクを明示的に解決したい場合とそうでない場合があります。
非シンボリックファイルまたは名前へのシンボリックリンクのチェーンの最後に到達する。これにより、絶対パス名が生成される場合と生成されない場合があります。そして、それを絶対パス名に解決したい場合とそうでない場合があります。
readlink foo
オプションのないコマンドfoo
は、その引数がシンボリックリンクであり、その回答がそのシンボリックリンクの値である場合にのみ回答を提供します。他のリンクはたどられません。答えは相対パスかもしれません:symlink引数の値は何でも。
ただし、readlink
すべてのファイルで機能するオプション(-f -eまたは-m)があり、実際に引数で示されるファイルに1つの絶対パス名(シンボリックリンクのないもの)を指定します。
これは、シンボリックリンクでないものには問題なく機能しますが、パスの中間シンボリックリンクを解決せずに絶対パス名を使用したい場合があります。これはコマンドによって行われますrealpath -s foo
シンボリックリンク引数の場合readlink
、そのオプションを使用すると、引数への絶対パス上のすべてのシンボリックリンクが再度解決されますが、引数値の後に発生する可能性のあるすべてのシンボリックリンクも含まれます。引数のリンク先ではなく、引数のシンボリックリンク自体への絶対パスが必要な場合は、そうしたくないかもしれません。ここでも、foo
シンボリックリンクの場合realpath -s foo
、引数として指定されたものを含め、シンボリックリンクを解決せずに絶対パスを取得します。
なければ-s
オプション、realpath
ほとんどのように同じことを
readlink
単にリンクの価値だけでなく、いくつかの他のものを読んだ以外、。なぜreadlink
そのオプションがあり、明らかにで望ましくない冗長性が生じるの
か、私にははっきりしませんrealpath
。
システムを横断していくつかのバリエーションがあるかもしれないことを除いて、ウェブを探索することはそれほど多くを語りません。
結論:realpath
少なくともここで要求された用途に対して、最も柔軟性が高く、使用するのに最適なコマンドです。
他のユーティリティ(coreutilsパッケージ)の存在を示唆していないため、私のお気に入りのソリューションは@EugenKonkovによるものでした。
しかし、相対パス "。"は失敗しました。および「..」なので、これらの特殊なケースを処理するわずかに改善されたバージョンを次に示します。
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
}
オイゲンの答えは私にとってはうまくいきませんでしたが、これはうまくいきました:
absolute="$(cd $(dirname \"$file\"); pwd)/$(basename \"$file\")"
ちなみに、現在の作業ディレクトリは影響を受けません。
最善の解決策であるimhoは、https://stackoverflow.com/a/3373298/9724628に投稿されているものです。
動作にはpythonが必要ですが、エッジケースのすべてまたはほとんどをカバーしており、非常に移植可能なソリューションであるようです。
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
realpathが存在せず、readlinkが絶対パスを出力できないMac OS Xで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[*]}"
)
}
(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
相対パスがディレクトリパスである場合、私のものを試してください、最も良いはずです:
absPath=$(pushd ../SOME_RELATIVE_PATH_TO_Directory > /dev/null && pwd && popd > /dev/null)
echo $absPath
echo "mydir/doc/ mydir/usoe ./mydir/usm" | awk '{ split($0,array," "); for(i in array){ system("cd "array[i]" && echo $PWD") } }'
@ ernest-aのかなり良いバージョンの改善:
absolute_path() {
cd "$(dirname "$1")"
case $(basename $1) in
..) echo "$(dirname $(pwd))";;
.) echo "$(pwd)";;
*) echo "$(pwd)/$(basename $1)";;
esac
}
正しくパスの最後の要素がある場合と、この取引..
その場合には、"$(pwd)/$(basename "$1")"
中@アーネスト-Aの答えのように通ってくるだろうaccurate_sub_path/spurious_subdirectory/..
。
これは、他のすべてからのチェーンソリューションです。たとえば、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")" "${?}"
相対パス$ lineにbash文字列置換を使用できます。
line=$(echo ${line/#..\//`cd ..; pwd`\/})
line=$(echo ${line/#.\//`pwd`\/})
echo $line
基本的な文字列前置置換は、
$ {string /#substring / replacement}の公式に従います。
これは、ここで詳しく説明されています。https://www.tldp.org/LDP/abs/html/string-manipulation.html
\
文字は否定し/
、我々はそれが我々が検索/置換する文字列の一部になりたいとき。
Mac OS Catalina、Ubuntu 16、Centos 7の間で適切に移植できるソリューションを見つけることができなかったので、Pythonインラインで実行することを決定し、私のbashスクリプトでうまく機能しました。
to_abs_path() {
python -c "import os; print os.path.abspath('$1')"
}
to_abs_path "/some_path/../secrets"