OS X에서 Bash 스크립트 절대 경로
OS X에서 현재 실행 중인 스크립트에 대한 절대 경로를 얻으려고 합니다.
많은 댓글들이 올라오고 있어요.readlink -f $0
OS의 ,, OS X의 ,는readlink
BSD와 동일하지만 동작하지 않습니다(GNU 버전에서는 동작합니다).
바로 사용할 수 있는 솔루션이 있습니까?
다음의 3개의 간단한 스텝으로, 이 문제와 그 외의 OS X의 많은 문제를 해결할 수 있습니다.
- 홈브루 설치
brew install coreutils
grealpath .
3)은 (3)으로 수 realpath
(2) (2) 「」를 참조해 주세요.
게 요.realpath()
C 기능은 작동하지만 명령줄에서 사용할 수 있는 기능이 없습니다.여기 간단한 대체 방법이 있습니다.
#!/bin/bash
realpath() {
[[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"
}
realpath "$0"
할 수 ./
않은 상대 에 ' 경로'가 붙습니다$PWD
★★★★★★★★★★★★★★★★★.#./
./
$1
.
가지 이 좀 하다는 것을 .
특히 심볼릭 링크의 여러 단계를 해결하지 않고 매우 "Bash-y"입니다.
번째 에서는 " 스크립트를 명시적으로 의 BSD와 비GNU에 하고 있습니다.readlink
.
여기에서는 임의의 수의 심볼릭링크를 해결하는 합리적인 이식성(bash를 'sh'와 대시로 체크)을 시도합니다.경로 내의 공백 공간에서도 동작합니다.
편집되어 되어 있습니다.local
솔루션입니다.POSIX를 소개합니다.인라인 함수가 아닌 서브셸 함수로 변경하여 변수 범위 지정에 대응하도록 편집했습니다.집하편
#!/bin/sh
realpath() (
OURPWD=$PWD
cd "$(dirname "$1")"
LINK=$(readlink "$(basename "$1")")
while [ "$LINK" ]; do
cd "$(dirname "$LINK")"
LINK=$(readlink "$(basename "$1")")
done
REALPATH="$PWD/$(basename "$1")"
cd "$OURPWD"
echo "$REALPATH"
)
realpath "$@"
그것이 누군가에게 도움이 될 수 있기를 바랍니다.
Python 솔루션의 보다 명령줄 친화적인 변형:
python -c 'import os, sys; print(os.path.realpath(sys.argv[1]))' ./my/path
다른 사람들이 지적한 것처럼 진정한 경로가 있기 때문에:
// realpath.c
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char* argv[])
{
if (argc > 1) {
for (int argIter = 1; argIter < argc; ++argIter) {
char *resolved_path_buffer = NULL;
char *result = realpath(argv[argIter], resolved_path_buffer);
puts(result);
if (result != NULL) {
free(result);
}
}
}
return 0;
}
파일 만들기:
#Makefile
OBJ = realpath.o
%.o: %.c
$(CC) -c -o $@ $< $(CFLAGS)
realpath: $(OBJ)
gcc -o $@ $^ $(CFLAGS)
음음음음 with with with with with with with with로 편찬해보세요.make
하다
ln -s $(pwd)/realpath /usr/local/bin/realpath
모든 답변을 확인했지만, Jason S Jul 14'16의 IMHO를 3:12에 놓쳐 코멘트 필드를 떠났습니다.
나 같은 사람이 답을 확인하는 경향이 있어서 모든 코멘트를 일일이 살펴볼 시간이 없는 경우:
$( cd "$(dirname "$0")" ; pwd -P )
도움말:
NAME
pwd -- return working directory name
SYNOPSIS
pwd [-L | -P]
DESCRIPTION
The pwd utility writes the absolute pathname of the current working
directory to the standard output.
Some shells may provide a builtin pwd command which is similar or identi-
cal to this utility. Consult the builtin(1) manual page.
The options are as follows:
-L Display the logical current working directory.
-P Display the physical current working directory (all symbolic
links resolved).
abs_path () {
echo "$(cd $(dirname "$1");pwd)/$(basename "$1")"
}
dirname
는, 을 「(디렉토리명칭은 「Directory Name」입니다./path/to/file
discriptions./path/to
.
cd /path/to; pwd
는 패스가 절대임을 보증합니다.
basename
에서는 파일 만 알 수 ./path/to/file
말해 네.file
.
시스템 프로비저닝 스크립트에서 사용할 솔루션을 찾고 있었습니다.즉, Homebrew가 설치되기도 전에 실행되었습니다.적절한 솔루션이 없기 때문에 작업을 크로스 플랫폼 언어로 오프로드합니다.예를 들어 Perl)로 오프로드합니다.
script_abspath=$(perl -e 'use Cwd "abs_path"; print abs_path(@ARGV[0])' -- "$0")
대부분의 경우 실제로 필요한 것은 다음과 같은 디렉토리입니다.
here=$(perl -e 'use File::Basename; use Cwd "abs_path"; print dirname(abs_path(@ARGV[0]));' -- "$0")
Python을 사용하면 다음과 같이 얻을 수 있습니다.
#!/usr/bin/env python
import os
import sys
print(os.path.realpath(sys.argv[1]))
Mac OS X의 realpath
realpath() {
path=`eval echo "$1"`
folder=$(dirname "$path")
echo $(cd "$folder"; pwd)/$(basename "$path");
}
관련 경로의 예:
realpath "../scripts/test.sh"
홈 폴더의 예
realpath "~/Test/../Test/scripts/test.sh"
위에서 보시는 것처럼 6개월 전에 이걸 찍었습니다.나는 다시 비슷한 것이 필요하다는 것을 알게 될 때까지 그것에 대해 까맣게 잊고 있었다.저는 그것이 얼마나 초보적인지 보고 완전히 놀랐습니다.저는 약 1년 동안 집중적으로 코드를 익혔지만, 상황이 최악일 때는 아무것도 배우지 못한 것 같은 기분이 들 때가 종종 있습니다.
저는 위의 '해결책'을 없애고 싶지만, 지난 몇 달 동안 제가 얼마나 많은 것을 배웠는지 보여주는 기록인 것이 정말 좋습니다.
하지만 나는 주제에서 벗어났군.어젯밤에 앉아서 다 풀었어.코멘트의 설명은 충분합니다.제가 계속 작업하고 있는 복사본을 추적하려면 다음 요점을 따르십시오.이 정도면 충분할 거야
#!/bin/sh # dash bash ksh # !zsh (issues). G. Nixon, 12/2013. Public domain.
## 'linkread' or 'fullpath' or (you choose) is a little tool to recursively
## dereference symbolic links (ala 'readlink') until the originating file
## is found. This is effectively the same function provided in stdlib.h as
## 'realpath' and on the command line in GNU 'readlink -f'.
## Neither of these tools, however, are particularly accessible on the many
## systems that do not have the GNU implementation of readlink, nor ship
## with a system compiler (not to mention the requisite knowledge of C).
## This script is written with portability and (to the extent possible, speed)
## in mind, hence the use of printf for echo and case statements where they
## can be substituded for test, though I've had to scale back a bit on that.
## It is (to the best of my knowledge) written in standard POSIX shell, and
## has been tested with bash-as-bin-sh, dash, and ksh93. zsh seems to have
## issues with it, though I'm not sure why; so probably best to avoid for now.
## Particularly useful (in fact, the reason I wrote this) is the fact that
## it can be used within a shell script to find the path of the script itself.
## (I am sure the shell knows this already; but most likely for the sake of
## security it is not made readily available. The implementation of "$0"
## specificies that the $0 must be the location of **last** symbolic link in
## a chain, or wherever it resides in the path.) This can be used for some
## ...interesting things, like self-duplicating and self-modifiying scripts.
## Currently supported are three errors: whether the file specified exists
## (ala ENOENT), whether its target exists/is accessible; and the special
## case of when a sybolic link references itself "foo -> foo": a common error
## for beginners, since 'ln' does not produce an error if the order of link
## and target are reversed on the command line. (See POSIX signal ELOOP.)
## It would probably be rather simple to write to use this as a basis for
## a pure shell implementation of the 'symlinks' util included with Linux.
## As an aside, the amount of code below **completely** belies the amount
## effort it took to get this right -- but I guess that's coding for you.
##===-------------------------------------------------------------------===##
for argv; do :; done # Last parameter on command line, for options parsing.
## Error messages. Use functions so that we can sub in when the error occurs.
recurses(){ printf "Self-referential:\n\t$argv ->\n\t$argv\n" ;}
dangling(){ printf "Broken symlink:\n\t$argv ->\n\t"$(readlink "$argv")"\n" ;}
errnoent(){ printf "No such file: "$@"\n" ;} # Borrow a horrible signal name.
# Probably best not to install as 'pathfull', if you can avoid it.
pathfull(){ cd "$(dirname "$@")"; link="$(readlink "$(basename "$@")")"
## 'test and 'ls' report different status for bad symlinks, so we use this.
if [ ! -e "$@" ]; then if $(ls -d "$@" 2>/dev/null) 2>/dev/null; then
errnoent 1>&2; exit 1; elif [ ! -e "$@" -a "$link" = "$@" ]; then
recurses 1>&2; exit 1; elif [ ! -e "$@" ] && [ ! -z "$link" ]; then
dangling 1>&2; exit 1; fi
fi
## Not a link, but there might be one in the path, so 'cd' and 'pwd'.
if [ -z "$link" ]; then if [ "$(dirname "$@" | cut -c1)" = '/' ]; then
printf "$@\n"; exit 0; else printf "$(pwd)/$(basename "$@")\n"; fi; exit 0
fi
## Walk the symlinks back to the origin. Calls itself recursivly as needed.
while [ "$link" ]; do
cd "$(dirname "$link")"; newlink="$(readlink "$(basename "$link")")"
case "$newlink" in
"$link") dangling 1>&2 && exit 1 ;;
'') printf "$(pwd)/$(basename "$link")\n"; exit 0 ;;
*) link="$newlink" && pathfull "$link" ;;
esac
done
printf "$(pwd)/$(basename "$newlink")\n"
}
## Demo. Install somewhere deep in the filesystem, then symlink somewhere
## else, symlink again (maybe with a different name) elsewhere, and link
## back into the directory you started in (or something.) The absolute path
## of the script will always be reported in the usage, along with "$0".
if [ -z "$argv" ]; then scriptname="$(pathfull "$0")"
# Yay ANSI l33t codes! Fancy.
printf "\n\033[3mfrom/as: \033[4m$0\033[0m\n\n\033[1mUSAGE:\033[0m "
printf "\033[4m$scriptname\033[24m [ link | file | dir ]\n\n "
printf "Recursive readlink for the authoritative file, symlink after "
printf "symlink.\n\n\n \033[4m$scriptname\033[24m\n\n "
printf " From within an invocation of a script, locate the script's "
printf "own file\n (no matter where it has been linked or "
printf "from where it is being called).\n\n"
else pathfull "$@"
fi
하게 처리할 수 있는 를 사용하는 입니다.realpath
필요하니까.이것이 필요하기 때문에brew install coreutils
그 단계를 자동화했습니다.을 사용하다
#!/usr/bin/env bash
set -e
if ! which realpath >&/dev/null; then
if ! which brew >&/dev/null; then
msg="ERROR: This script requires brew. See https://brew.sh for installation instructions."
echo "$(tput setaf 1)$msg$(tput sgr0)" >&2
exit 1
fi
echo "Installing coreutils/realpath"
brew install coreutils >&/dev/null
fi
thisDir=$( dirname "`realpath "$0"`" )
echo "This script is run from \"$thisDir\""
에러는 에러, 에러가 합니다.brew
를 인스톨 할 수도 있습니다만, 그 이외의 방법으로 인스톨 할 수도 있습니다.그냥 인터넷에서 임의의 루비 코드를 감아주는 자동화가 불편했어요.
이것은 올레그 미키예프의 대답에 대한 자동 변형입니다.
하나의 중요한 테스트
이러한 솔루션의 적절한 테스트의 1개는 다음과 같습니다.
- 어딘가에 코드를 스크립트 파일에 넣다
- 심볼링크')
ln -s
)을합니다. - 해당 심볼링크에서 스크립트 실행
솔루션은 심볼 링크를 참조 해제하고 원본 디렉터리를 제공합니까?그렇다면 효과가 있습니다.
이것은 OSX에서 동작하는 것처럼 보이며 바이너리가 필요 없으며 여기서 가져온 것입니다.
function normpath() {
# Remove all /./ sequences.
local path=${1//\/.\//\/}
# Remove dir/.. sequences.
while [[ $path =~ ([^/][^/]*/\.\./) ]]; do
path=${path/${BASH_REMATCH[0]}/}
done
echo $path
}
마음에 들어요.
#!/usr/bin/env bash
function realpath() {
local _X="$PWD"
local _LNK=$1
cd "$(dirname "$_LNK")"
if [ -h "$_LNK" ]; then
_LNK="$(readlink "$_LNK")"
cd "$(dirname "$_LNK")"
fi
echo "$PWD/$(basename "$_LNK")"
cd "$_X"
}
는 난필이 필요했다.realpath
OS X에서의 치환(Symblinks 및 상위 참조가 있는 경로에서 정상적으로 동작하는 OS X에서의 치환).여기에는 예를 들어 홈브루를 설치한 경우 등 상위 참조를 해결하기 전에 경로의 심볼 링크를 해결하는 작업이 포함됩니다.coreutils
병, 실행:
$ ln -s /var/log/cups /tmp/linkeddir # symlink to another directory
$ greadlink -f /tmp/linkeddir/.. # canonical path of the link parent
/private/var/log
주의:readlink -f
해결했습니다/tmp/linkeddir
문제를 해결하기 전에..
parent dir 참조.물론 없습니다.readlink -f
Mac에서도 마찬가지입니다.
따라서 bash 구현의 일부로서realpath
GNUlib 함수 호출이 하는 것을 Bash 3.2에서 다시 구현했습니다.이것은 GNU가 하는 함수 호출이기도 합니다.readlink -f
라이선스:
# shellcheck shell=bash
set -euo pipefail
_contains() {
# return true if first argument is present in the other arguments
local elem value
value="$1"
shift
for elem in "$@"; do
if [[ $elem == "$value" ]]; then
return 0
fi
done
return 1
}
_canonicalize_filename_mode() {
# resolve any symlink targets, GNU readlink -f style
# where every path component except the last should exist and is
# resolved if it is a symlink. This is essentially a re-implementation
# of canonicalize_filename_mode(path, CAN_ALL_BUT_LAST).
# takes the path to canonicalize as first argument
local path result component seen
seen=()
path="$1"
result="/"
if [[ $path != /* ]]; then # add in current working dir if relative
result="$PWD"
fi
while [[ -n $path ]]; do
component="${path%%/*}"
case "$component" in
'') # empty because it started with /
path="${path:1}" ;;
.) # ./ current directory, do nothing
path="${path:1}" ;;
..) # ../ parent directory
if [[ $result != "/" ]]; then # not at the root?
result="${result%/*}" # then remove one element from the path
fi
path="${path:2}" ;;
*)
# add this component to the result, remove from path
if [[ $result != */ ]]; then
result="$result/"
fi
result="$result$component"
path="${path:${#component}}"
# element must exist, unless this is the final component
if [[ $path =~ [^/] && ! -e $result ]]; then
echo "$1: No such file or directory" >&2
return 1
fi
# if the result is a link, prefix it to the path, to continue resolving
if [[ -L $result ]]; then
if _contains "$result" "${seen[@]+"${seen[@]}"}"; then
# we've seen this link before, abort
echo "$1: Too many levels of symbolic links" >&2
return 1
fi
seen+=("$result")
path="$(readlink "$result")$path"
if [[ $path = /* ]]; then
# if the link is absolute, restart the result from /
result="/"
elif [[ $result != "/" ]]; then
# otherwise remove the basename of the link from the result
result="${result%/*}"
fi
elif [[ $path =~ [^/] && ! -d $result ]]; then
# otherwise all but the last element must be a dir
echo "$1: Not a directory" >&2
return 1
fi
;;
esac
done
echo "$result"
}
여기에는 순환 심볼링크 검출, 같은 (중간) 경로가 두 번 나타나면 종료가 포함됩니다.
한 것은 ★★★★★★★★★★★★★★★★★★★」readlink -f
그럼 위의 내용을 다음과 같이 사용할 수 있습니다.
readlink() {
if [[ $1 != -f ]]; then # poor-man's option parsing
# delegate to the standard readlink command
command readlink "$@"
return
fi
local path result seenerr
shift
seenerr=
for path in "$@"; do
# by default readlink suppresses error messages
if ! result=$(_canonicalize_filename_mode "$path" 2>/dev/null); then
seenerr=1
continue
fi
echo "$result"
done
if [[ $seenerr ]]; then
return 1;
fi
}
★★★의 realpath
도 needed needed needed , , ,가 했다.--relative-to
★★★★★★★★★★★★★★★★★」--relative-base
: 후 경로를 제공합니다.
_realpath() {
# GNU realpath replacement for bash 3.2 (OS X)
# accepts --relative-to= and --relative-base options
# and produces canonical (relative or absolute) paths for each
# argument on stdout, errors on stderr, and returns 0 on success
# and 1 if at least 1 path triggered an error.
local relative_to relative_base seenerr path
relative_to=
relative_base=
seenerr=
while [[ $# -gt 0 ]]; do
case $1 in
"--relative-to="*)
relative_to=$(_canonicalize_filename_mode "${1#*=}")
shift 1;;
"--relative-base="*)
relative_base=$(_canonicalize_filename_mode "${1#*=}")
shift 1;;
*)
break;;
esac
done
if [[
-n $relative_to
&& -n $relative_base
&& ${relative_to#${relative_base}/} == "$relative_to"
]]; then
# relative_to is not a subdir of relative_base -> ignore both
relative_to=
relative_base=
elif [[ -z $relative_to && -n $relative_base ]]; then
# if relative_to has not been set but relative_base has, then
# set relative_to from relative_base, simplifies logic later on
relative_to="$relative_base"
fi
for path in "$@"; do
if ! real=$(_canonicalize_filename_mode "$path"); then
seenerr=1
continue
fi
# make path relative if so required
if [[
-n $relative_to
&& ( # path must not be outside relative_base to be made relative
-z $relative_base || ${real#${relative_base}/} != "$real"
)
]]; then
local common_part parentrefs
common_part="$relative_to"
parentrefs=
while [[ ${real#${common_part}/} == "$real" ]]; do
common_part="$(dirname "$common_part")"
parentrefs="..${parentrefs:+/$parentrefs}"
done
if [[ $common_part != "/" ]]; then
real="${parentrefs:+${parentrefs}/}${real#${common_part}/}"
fi
fi
echo "$real"
done
if [[ $seenerr ]]; then
return 1
fi
}
if ! command -v realpath > /dev/null 2>&1; then
# realpath is not available on OSX unless you install the `coreutils` brew
realpath() { _realpath "$@"; }
fi
이 코드에 대한 코드 리뷰 요청에 유닛 테스트를 포함시켰습니다.
bash를 사용하는 Mac에서 nodejs 개발자의 경우:
realpath() {
node -p "fs.realpathSync('$1')"
}
★★★★★★★★★★의 사용법pushd
:
realpath() {
eval echo "$(pushd $(dirname "$1") | cut -d' ' -f1)/$(basename "$1")"
}
eval
다음과 같은 칠데를 확장하기 위해 사용됩니다.~/Downloads
.
코멘터와의 커뮤니케이션에 근거해, Ubuntu와 완전히 같은 리얼 패스를 실장하는 3가지 방법이 없고, 매우 어렵다고 하는 것에 동의했습니다.
하지만 다음 버전에서는 가장 좋은 답변은 할 수 없고 맥북에 대한 나의 일상의 요구를 충족시킬 수 있습니다.이 코드를 ~/.bashrc에 입력하고 다음 사항을 기억하십시오.
- arg는 1개의 파일 또는 dir만 사용할 수 있으며 와일드카드 없음
- dir 또는 파일 이름에 공백 없음
- 적어도 파일 또는 dir의 부모 dir가 존재합니다.
- 얼마든지 사용하세요. / 이것들, 이것들은 안전합니다.
# 1. if is a dir, try cd and pwd
# 2. if is a file, try cd its parent and concat dir+file
realpath() {
[ "$1" = "" ] && return 1
dir=`dirname "$1"`
file=`basename "$1"`
last=`pwd`
[ -d "$dir" ] && cd $dir || return 1
if [ -d "$file" ];
then
# case 1
cd $file && pwd || return 1
else
# case 2
echo `pwd`/$file | sed 's/\/\//\//g'
fi
cd $last
}
언급URL : https://stackoverflow.com/questions/3572030/bash-script-absolute-path-with-os-x
'programing' 카테고리의 다른 글
iPhone/iOS에서 전화번호의 파란색 스타일을 제거하려면 어떻게 해야 합니까? (0) | 2023.04.20 |
---|---|
XAML의 Self/'this'에 대한 바인딩 (0) | 2023.04.20 |
SSH 공용 키에 액세스하려면 어떻게 해야 하나요? (0) | 2023.04.20 |
목표-C - 문자열에서 마지막 문자 제거 (0) | 2023.04.20 |
SQL Server에서 한 달 동안의 일수를 확인하는 방법 (0) | 2023.04.20 |