답변:
를 사용하면 다음과 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' "$@"
}
즉 더 GNU의처럼 행동 것 readlink -f
보다는 realpath()
(GNU readlink -e
파일만큼의 dirname이이처럼 존재하지 않는 경우는 불평하지 않을 것이다에).
.zshrc
: 대신 이 게시물을 참조하십시오 .
zsh에서는 다음을 수행 할 수 있습니다.
mypath=${0:a}
또는 스크립트가있는 디렉토리를 가져 오려면 다음을 수행하십시오.
mydir=${0:a:h}
출처 : zshexpn (1) 매뉴얼 페이지, HISTORY EXPANSION 섹션, 하위 섹션 수정 자 (또는 간단히 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
에서 홈 디렉토리 ( /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 .
. 다음 과 같이 절대 전류로 설정할 수 있습니다 . 나는 그것이 bourneshell에서 작동할지 의심합니다. 그러나 그것은 당신이 처음 테스트 한 모든 것에서 작동해야합니다. 어쨌든 나를 위해 않습니다.
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은 단일을 제공합니다 ?
). 나는 오래된 상용 Unices에서도 그것을 보았다고 생각합니다.
현재 디렉토리 또는 쉘 스크립트를 실행 한 디렉토리에 대한 실행 권한이있는 경우 디렉토리에 대한 절대 경로를 원하는 경우 cd
.
-P
옵션이 유효 하다면,$PWD
환경 변수는로 출력 될 문자열로 설정되어야한다pwd -P
. 현재 작업 디렉토리를 판별하기 위해 새 디렉토리 또는 해당 디렉토리의 상위에 대한 권한이 충분하지 않은 경우$PWD
환경 변수 의 값 이 지정되지 않습니다.
표준 출력에 기록 된 경로명에는 기호 링크 유형의 파일을 참조하는 구성 요소가 포함되지 않아야합니다.
pwd
유틸리티가 표준 출력에 쓸 수 있는 여러 경로 이름이있는 경우 (하나는 단일 / 슬래시 문자로 시작하고 하나는 두 개의 / 슬래시 문자로 시작), 단일 / 슬래시 문자로 시작하는 경로 이름을 작성해야합니다. 경로명은 앞뒤에 하나 또는 두 개의 / 슬래시 문자 다음에 불필요한 / 슬래시 문자를 포함하지 않아야합니다.
때문입니다 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
존재하지 않고 소프트 링크가 아닌지 점검합니다 . 참이면 인쇄합니다.
이런 식 $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' -> ...
알고리즘을 재정의하는 것을 막기 위해 파이썬을 사용할 수있을 때 동정적인 원 라이너는 어떻습니까?
function readlink { python -c "import os.path; print os.path.realpath('$1')"; }