나는 변환 할 /foo/bar/..
에/foo
이것을 수행하는 bash 명령이 있습니까?
편집 : 실제 경우에는 디렉토리가 존재합니다.
/foo/bar/..
에를 /foo
하고 사용하여 bash
명령을. 언급되지 않은 다른 요구 사항이있는 경우, 아마도 다음과 같아야합니다.
나는 변환 할 /foo/bar/..
에/foo
이것을 수행하는 bash 명령이 있습니까?
편집 : 실제 경우에는 디렉토리가 존재합니다.
/foo/bar/..
에를 /foo
하고 사용하여 bash
명령을. 언급되지 않은 다른 요구 사항이있는 경우, 아마도 다음과 같아야합니다.
답변:
경로에서 파일 이름의 일부를 잘라내려면 "dirname"과 "basename"이 친구이며 "realpath"도 편리합니다.
dirname /foo/bar/baz
# /foo/bar
basename /foo/bar/baz
# baz
dirname $( dirname /foo/bar/baz )
# /foo
realpath ../foo
# ../foo: No such file or directory
realpath /tmp/../tmp/../tmp
# /tmp
realpath
대안
realpath
쉘에서 지원하지 않는 경우 시도해 볼 수 있습니다
readlink -f /path/here/..
또한
readlink -m /path/there/../../
와 동일하게 작동
realpath -s /path/here/../../
경로를 정규화하기 위해 존재할 필요가 없다는 점에서
realpath
와 readlink
GNU 기본 유틸리티에서 온다, 그래서 대부분의 아마 당신도 모두 또는 아무것도 얻을 수 없습니다. 내가 올바르게 기억한다면 Mac의 readlink 버전은 GNU 버전과 약간 다릅니다 :-\
이 작업을 수행하는 직접 bash 명령이 있는지 모르겠지만 일반적으로 수행합니다.
normalDir="`cd "${dirToNormalize}";pwd`"
echo "${normalDir}"
잘 작동합니다.
rm -rf $normalDir
dirToNormalize가 없으면 매우 위험 할 수 있습니다 ( )!
&&
@DavidBlevins의 의견에 따라 를 사용하는 것이 가장 좋습니다 .
시도하십시오 realpath
. 아래는 공개 소스에 기증 된 전체 소스입니다.
// realpath.c: display the absolute path to a file or directory.
// Adam Liss, August, 2007
// This program is provided "as-is" to the public domain, without express or
// implied warranty, for any non-profit use, provided this notice is maintained.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libgen.h>
#include <limits.h>
static char *s_pMyName;
void usage(void);
int main(int argc, char *argv[])
{
char
sPath[PATH_MAX];
s_pMyName = strdup(basename(argv[0]));
if (argc < 2)
usage();
printf("%s\n", realpath(argv[1], sPath));
return 0;
}
void usage(void)
{
fprintf(stderr, "usage: %s PATH\n", s_pMyName);
exit(1);
}
realpath
. 또한 내가 가장 좋아하는 것이지만 소스에서 도구를 작성하는 대신. 그것은 모두 헤비급이며, 대부분의 시간은 readlink -f
... BTW readlink
는 bash 내장이 아니라 coreutils
우분투의 일부입니다 .
이식성이 뛰어나고 안정적인 솔루션은 파이썬을 사용하는 것입니다. 파이썬은 다윈을 포함하여 거의 모든 곳에 사전 설치되어 있습니다. 두 가지 옵션이 있습니다.
abspath
절대 경로를 반환하지만 심볼릭 링크를 확인하지 않습니다.
python -c "import os,sys; print(os.path.abspath(sys.argv[1]))" path/to/file
realpath
절대 경로를 반환하면 심볼릭 링크가 해결되어 표준 경로가 생성됩니다.
python -c "import os,sys; print(os.path.realpath(sys.argv[1]))" path/to/file
각각의 경우 path/to/file
상대 또는 절대 경로 일 수 있습니다.
coreutils 패키지의 readlink 유틸리티를 사용하십시오.
MY_PATH=$(readlink -f "$0")
readlink
절대 경로를 얻기위한 bash 표준입니다. 또한 경로 또는 경로가 존재하지 않는 경우 빈 플래그를 반환하는 이점이 있습니다 (플래그가 제공됨).
존재하거나 존재하지 않을 수 있지만 부모가있는 디렉토리에 대한 절대 경로를 얻으려면 다음을 사용하십시오.
abspath=$(readlink -f $path)
모든 부모와 함께 존재해야하는 디렉토리의 절대 경로를 얻으려면 다음을 수행하십시오.
abspath=$(readlink -e $path)
주어진 경로를 정식화하고 존재하는 경우 심볼릭 링크를 따르지만 누락 된 디렉토리를 무시하고 경로를 반환하려면 다음과 같습니다.
abspath=$(readlink -m $path)
유일한 단점은 readlink가 링크를 따른다는 것입니다. 링크를 따르지 않으려면 다음 대체 규칙을 사용할 수 있습니다.
abspath=$(cd ${path%/*} && echo $PWD/${path##*/})
$ path의 디렉토리 부분으로 chdir하고 $ path의 파일 부분과 함께 현재 디렉토리를 인쇄합니다. chdir에 실패하면 빈 문자열과 stderr에 오류가 발생합니다.
readlink
가능한 경우 좋은 옵션입니다. OS X 버전은 -e
또는 -f
옵션을 지원하지 않습니다 . 처음 세 가지 예에서는 $path
파일 이름에서 공백이나 와일드 카드를 처리하기 위해 큰 따옴표를 묶어야합니다 . 매개 변수 확장의 경우 +1이지만 보안 취약점이 있습니다. path
비어 있으면 cd
홈 디렉토리로 이동합니다. 큰 따옴표가 필요합니다. abspath=$(cd "${path%/*}" && echo "$PWD/${path##*/}")
오래된 질문이지만 쉘 수준에서 전체 경로 이름 을 처리 하는 경우 훨씬 간단한 방법 이 있습니다 .
abspath = "$ (cd"$ path "&& pwd)"
CD는 서브 쉘에서 발생하므로 기본 스크립트에 영향을 미치지 않습니다.
쉘 내장 명령이 -L 및 -P를 허용한다고 가정하면 다음과 같은 두 가지 변형이 있습니다.
abspath = "$ (cd -P"$ path "&& pwd -P)" "# 심볼릭 링크가 해결 된 물리적 경로 abspath = "$ (cd -L"$ path "&& pwd -L)" "# 논리적 경로 보존 심볼릭 링크
개인적으로, 어떤 이유로 든 상징적 인 링크에 매료되지 않으면 나중에이 접근법이 거의 필요하지 않습니다.
참고 : 스크립트가 현재 디렉토리를 나중에 변경하더라도 작동하는 스크립트의 시작 디렉토리를 얻는 변형.
name0 = "$ (기본 이름"$ 0 ")"; # 기본 스크립트 이름 dir0 = "$ (cd"$ (dirname "$ 0") ""&& pwd) "; # 절대 시작 디렉토리
CD를 사용하면 스크립트가 ./script.sh와 같은 명령으로 실행 되더라도 cd / pwd없이 종종 ..를 제공하는 경우에도 항상 절대 디렉토리를 갖게됩니다. 스크립트가 나중에 CD를 수행하는 경우에는 쓸모가 없습니다.
Adam Liss가 언급했듯이 realpath
모든 배포판에 번들로 제공되는 것은 아닙니다. 이것이 가장 좋은 해결책이기 때문에 부끄러운 일입니다. 제공된 소스 코드가 훌륭하므로 지금 사용하기 시작할 것입니다. 여기까지 내가 지금까지 사용해 왔던 내용이 있습니다.
get_abs_path() {
local PARENT_DIR=$(dirname "$1")
cd "$PARENT_DIR"
local ABS_PATH="$(pwd)"/"$(basename "$1")"
cd - >/dev/null
echo "$ABS_PATH"
}
당신이 해결의 심볼릭 링크를 원하는 경우에, 다만 교체 pwd
와 함께 pwd -P
.
pwd -P
이 경우에 대한 옵션을 가진 하나의 문제는 ... $(basename "$1")
다른 디렉토리에있는 파일에 대한 심볼릭 링크 인 경우 어떻게 될지 고려하십시오 . 는 pwd -P
단지 기본 이름 부분을 경로의 디렉토리 부분에 심볼릭 링크를 해결 있지만.
내 최근 해결책은 다음과 같습니다.
pushd foo/bar/..
dir=`pwd`
popd
Tim Whitcomb의 답변을 바탕으로합니다.
pushd $(dirname /usr/bin/java)
시도해 볼 수 있습니다.
정확히 대답은 아니지만 후속 질문 일 수도 있습니다 (원래 질문은 명시 적이 지 않음).
readlink
실제로 심볼릭 링크를 따르고 싶다면 괜찮습니다. 그러나 단순히 정상화에 대한 사용 사례도있다 ./
및 ../
및 //
순수 구문 적으로 수행 할 수 있습니다 시퀀스 없이 심볼릭 링크를 정규화는. readlink
이것에 좋지 않으며 둘 다 아닙니다 realpath
.
for f in $paths; do (cd $f; pwd); done
기존 경로에서는 작동하지만 다른 경로에서는 작동하지 않습니다.
sed
(스크립트는 반복적으로 시퀀스를 대체 할 수 있다는 점을 제외하고, 좋은 베팅이 될 것 같다 /foo/bar/baz/../..
-> /foo/bar/..
> - /foo
모든 시스템에 가정, 또는 어떤 추한 루프를 사용하여 출력 비교하는 것은 안전하지 않습니다 펄, 같은 것을 사용하지 않고) sed
로를 입력.
Java (JDK 6+)를 사용하는 단일 라이너 FWIW :
jrunscript -e 'for (var i = 0; i < arguments.length; i++) {println(new java.io.File(new java.io.File(arguments[i]).toURI().normalize()))}' $paths
realpath
이 -s
심볼릭 링크와 만 해결 참조를 해결하지에 옵션 /./
, /../
여분의 분리 /
문자. 이 -m
옵션 과 결합 realpath
하면 파일 이름에서만 작동하며 실제 파일은 건드리지 않습니다. 그것은 소리 완벽한 솔루션처럼. 그러나 아아, realpath
여전히 많은 시스템에서 누락되었습니다.
..
심볼릭 링크가 포함 된 경우 구성 요소를 구문 적으로 제거 할 수 없습니다. /one/two/../three
로 동일하지 않은 /one/three
경우 two
에 심볼릭 링크입니다 /foo/bar
.
나는 파티에 늦었지만 다음과 같이 많은 스레드를 읽은 후에 만들어진 솔루션입니다.
resolve_dir() {
(builtin cd `dirname "${1/#~/$HOME}"`'/'`basename "${1/#~/$HOME}"` 2>/dev/null; if [ $? -eq 0 ]; then pwd; fi)
}
이것은 $ 1의 절대 경로를 해결하고 ~로 잘 플레이하고 경로에 symlinks를 유지하며 디렉토리 스택을 망칠 수 없습니다. 전체 경로를 반환하거나 존재하지 않는 경우 아무것도 반환하지 않습니다. $ 1은 디렉토리가 될 것으로 예상하고 그렇지 않으면 실패 할 것입니다.하지만 쉽게 확인할 수 있습니다.
말이 많고 약간 늦었습니다. 오래된 RHEL4 / 5에 붙어 있기 때문에 하나를 작성해야합니다. 절대 및 상대 링크를 처리하고 //, /./ 및 somedir /../ 항목을 단순화합니다.
test -x /usr/bin/readlink || readlink () {
echo $(/bin/ls -l $1 | /bin/cut -d'>' -f 2)
}
test -x /usr/bin/realpath || realpath () {
local PATH=/bin:/usr/bin
local inputpath=$1
local changemade=1
while [ $changemade -ne 0 ]
do
changemade=0
local realpath=""
local token=
for token in ${inputpath//\// }
do
case $token in
""|".") # noop
;;
"..") # up one directory
changemade=1
realpath=$(dirname $realpath)
;;
*)
if [ -h $realpath/$token ]
then
changemade=1
target=`readlink $realpath/$token`
if [ "${target:0:1}" = '/' ]
then
realpath=$target
else
realpath="$realpath/$target"
fi
else
realpath="$realpath/$token"
fi
;;
esac
done
inputpath=$realpath
done
echo $realpath
}
mkdir -p /tmp/bar
(cd /tmp ; ln -s /tmp/bar foo; ln -s ../.././usr /tmp/bar/link2usr)
echo `realpath /tmp/foo`
GitHub에 배치 한 무료 Bash 라이브러리 제품인 realpath-lib 를 무료로 사용해보십시오 . 철저하게 문서화되어 있으며 훌륭한 학습 도구를 만듭니다.
로컬, 상대 및 절대 경로를 해결하고 Bash 4+를 제외한 종속성이 없습니다. 어디에서나 작동합니다. 무료이며 깨끗하고 단순하며 유익합니다.
넌 할 수있어:
get_realpath <absolute|relative|symlink|local file path>
이 기능은 라이브러리의 핵심입니다.
function get_realpath() {
if [[ -f "$1" ]]
then
# file *must* exist
if cd "$(echo "${1%/*}")" &>/dev/null
then
# file *may* not be local
# exception is ./file.ext
# try 'cd .; cd -;' *works!*
local tmppwd="$PWD"
cd - &>/dev/null
else
# file *must* be local
local tmppwd="$PWD"
fi
else
# file *cannot* exist
return 1 # failure
fi
# reassemble realpath
echo "$tmppwd"/"${1##*/}"
return 0 # success
}
또한 get_dirname, get_filename, get_ stemname 및 validate_path에 대한 함수도 포함합니다. 여러 플랫폼에서 사용해보고 개선에 도움이됩니다.
문제 realpath
는 BSD (또는 그 문제에 대한 OSX)에서 사용할 수 없다는 것입니다. 다음은 Linux Journal에서 다소 오래된 (2009) 기사에서 추출한 간단한 레시피입니다 .
function normpath() {
# Remove all /./ sequences.
local path=${1//\/.\//\/}
# Remove dir/.. sequences.
while [[ $path =~ ([^/][^/]*/\.\./) ]]; do
path=${path/${BASH_REMATCH[0]}/}
done
echo $path
}
이 변형 에는 경로가 필요 하지 않습니다 .
@Andre의 답변을 바탕으로 누군가가 루프가없는 완전 문자열 조작 기반 솔루션을 따르는 경우 약간 더 나은 버전이있을 수 있습니다. 또한 사용의 단점 어떤 심볼릭 링크, 역 참조하지 않으려는 사람들을 위해 유용 realpath
또는 readlink -f
.
bash 버전 3.2.25 이상에서 작동합니다.
shopt -s extglob
normalise_path() {
local path="$1"
# get rid of /../ example: /one/../two to /two
path="${path//\/*([!\/])\/\.\./}"
# get rid of /./ and //* example: /one/.///two to /one/two
path="${path//@(\/\.\/|\/+(\/))//}"
# remove the last '/.'
echo "${path%%/.}"
}
$ normalise_path /home/codemedic/../codemedic////.config
/home/codemedic/.config
hello/../world
(2) 파일 이름의 점 /hello/..world
(3) 이중 슬래시 후 점 /hello//../world
(4) 이중 슬래시 전후 점 /hello//./world
또는 /hello/.//world
(5) 현재 후 부모 : /hello/./../world/
(6) 부모 부모 후 : /hello/../../world
, 등 - 일부 이들의 경로가 변경 끝까지 수정을 위해 루프를 사용하여 고정 될 수있다. (또한 제거 dir/../
하지 /dir/..
만, 삭제 dir/..
끝에서.)
loveborg의 훌륭한 파이썬 스 니펫을 기반으로 다음과 같이 썼습니다.
#!/bin/sh
# Version of readlink that follows links to the end; good for Mac OS X
for file in "$@"; do
while [ -h "$file" ]; do
l=`readlink $file`
case "$l" in
/*) file="$l";;
*) file=`dirname "$file"`/"$l"
esac
done
#echo $file
python -c "import os,sys; print os.path.abspath(sys.argv[1])" "$file"
done
FILEPATH="file.txt"
echo $(realpath $(dirname $FILEPATH))/$(basename $FILEPATH)
파일이 존재하지 않더라도 작동합니다. 파일이 들어있는 디렉토리가 있어야합니다.
realpath -e
세 가지를 모두 수행하는 솔루션이 필요했습니다.
realpath
그리고 readlink -f
애드온입니다답은 # 1과 # 2를 모두 가지고 있지 않습니다. 다른 야크 면도를 줄이기 위해 # 3을 추가했습니다.
#!/bin/bash
P="${1?Specify a file path}"
[ -e "$P" ] || { echo "File does not exist: $P"; exit 1; }
while [ -h "$P" ] ; do
ls="$(ls -ld "$P")"
link="$(expr "$ls" : '.*-> \(.*\)$')"
expr "$link" : '/.*' > /dev/null &&
P="$link" ||
P="$(dirname "$P")/$link"
done
echo "$(cd "$(dirname "$P")"; pwd)/$(basename "$P")"
인용문을 완전히 연습하기 위해 경로에 약간의 공백이있는 짧은 테스트 사례가 있습니다.
mkdir -p "/tmp/test/ first path "
mkdir -p "/tmp/test/ second path "
echo "hello" > "/tmp/test/ first path / red .txt "
ln -s "/tmp/test/ first path / red .txt " "/tmp/test/ second path / green .txt "
cd "/tmp/test/ second path "
fullpath " green .txt "
cat " green .txt "
나는 이것이 고대의 질문이라는 것을 안다. 나는 여전히 대안을 제공하고 있습니다. 최근에 나는 같은 문제를 만났으며 기존의 휴대용 명령을 찾지 못했습니다. 그래서 나는 트릭을 수행 할 수있는 기능을 포함하는 다음 쉘 스크립트를 작성했습니다.
#! /bin/sh
function normalize {
local rc=0
local ret
if [ $# -gt 0 ] ; then
# invalid
if [ "x`echo $1 | grep -E '^/\.\.'`" != "x" ] ; then
echo $1
return -1
fi
# convert to absolute path
if [ "x`echo $1 | grep -E '^\/'`" == "x" ] ; then
normalize "`pwd`/$1"
return $?
fi
ret=`echo $1 | sed 's;/\.\($\|/\);/;g' | sed 's;/[^/]*[^/.]\+[^/]*/\.\.\($\|/\);/;g'`
else
read line
normalize "$line"
return $?
fi
if [ "x`echo $ret | grep -E '/\.\.?(/|$)'`" != "x" ] ; then
ret=`normalize "$ret"`
rc=$?
fi
echo "$ret"
return $rc
}
https://gist.github.com/bestofsong/8830bdf3e5eb9461d27313c3c282868c
나는 가능한 최고의 성능 (재미있게)에 초점을 맞춰 이것을 처리하기 위해 내장 전용 기능을 만들었습니다. 심볼릭 링크를 해결하지 않으므로 기본적으로와 동일합니다 realpath -sm
.
## A bash-only mimic of `realpath -sm`.
## Give it path[s] as argument[s] and it will convert them to clean absolute paths
abspath () {
${*+false} && { >&2 echo $FUNCNAME: missing operand; return 1; };
local c s p IFS='/'; ## path chunk, absolute path, input path, IFS for splitting paths into chunks
local -i r=0; ## return value
for p in "$@"; do
case "$p" in ## Check for leading backslashes, identify relative/absolute path
'') ((r|=1)); continue;;
//[!/]*) >&2 echo "paths =~ ^//[^/]* are impl-defined; not my problem"; ((r|=2)); continue;;
/*) ;;
*) p="$PWD/$p";; ## Prepend the current directory to form an absolute path
esac
s='';
for c in $p; do ## Let IFS split the path at '/'s
case $c in ### NOTE: IFS is '/'; so no quotes needed here
''|.) ;; ## Skip duplicate '/'s and '/./'s
..) s="${s%/*}";; ## Trim the previous addition to the absolute path string
*) s+=/$c;; ### NOTE: No quotes here intentionally. They make no difference, it seems
esac;
done;
echo "${s:-/}"; ## If xpg_echo is set, use `echo -E` or `printf $'%s\n'` instead
done
return $r;
}
참고 : 경로 시작시 //
정확히 두 개의 이중 슬래시가 구현 정의 동작이므로이 함수는로 시작하는 경로를 처리하지 않습니다 . 그러나, 처리 /
, ///
등 잘합니다.
이 함수는 모든 경우를 올바르게 처리하는 것처럼 보이지만 아직 처리하지 않은 부분이있을 수 있습니다.
성능 참고 : 수천 개의 인수와 함께 호출 될 abspath
때보 다 약 10 배 느리게 실행됩니다 realpath -sm
. 단일 인수로 호출하면 매번 새 프로그램을 실행할 필요가 없기 때문에 내 컴퓨터 abspath
보다 110 배 이상 빠르게 realpath -sm
실행됩니다.
오늘 stat
명령을 사용하여 경로 를 확인할 수 있음을 발견했습니다 .
"~ / Documents"와 같은 디렉토리의 경우 :
당신은 이것을 실행할 수 있습니다 :
stat -f %N ~/Documents
전체 경로를 얻으려면
/Users/me/Documents
심볼릭 링크의 경우 % Y 형식 옵션을 사용할 수 있습니다.
stat -f %Y example_symlink
다음과 같은 결과가 반환 될 수 있습니다.
/usr/local/sbin/example_symlink
다른 버전의 * NIX에서는 형식화 옵션이 다를 수 있지만 OSX에서는 나에게 적합했습니다.
stat -f %N ~/Documents
라인은 쉘이 대체 ... 붉은 청어 ~/Documents
로 /Users/me/Documents
, 그리고 stat
단지 그대로 인수를 인쇄합니다.
/foo/bar
심지어는 나/foo
실제로 존재, 또는 당신은 단지 경로 이름 규칙에 따라 문자열 조작 측면에 관심이 있습니까?