OS X에서 Bash 스크립트 절대 경로
OS X에서 현재 실행 중인 스크립트에 대한 절대 경로를 얻으려고 합니다.
많은 댓글들이 올라오고 있어요.readlink -f $0 OS의 ,, OS X의 ,는readlinkBSD와 동일하지만 동작하지 않습니다(GNU 버전에서는 동작합니다).
바로 사용할 수 있는 솔루션이 있습니까?
다음의 3개의 간단한 스텝으로, 이 문제와 그 외의 OS X의 많은 문제를 해결할 수 있습니다.
- 홈브루 설치
brew install coreutilsgrealpath .
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"
}
는 난필이 필요했다.realpathOS 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 -fMac에서도 마찬가지입니다.
따라서 bash 구현의 일부로서realpathGNUlib 함수 호출이 하는 것을 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 |