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/../../
경로를 정규화하기 위해 존재할 필요가 없다는 점에서
이 작업을 수행하는 직접 bash 명령이 있는지 모르겠지만 일반적으로 수행합니다.
normalDir="`cd "${dirToNormalize}";pwd`"
echo "${normalDir}"
잘 작동합니다.
시도하십시오
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);
}
이식성이 뛰어나고 안정적인 솔루션은 파이썬을 사용하는 것입니다. 파이썬은 다윈을 포함하여 거의 모든 곳에 사전 설치되어 있습니다. 두 가지 옵션이 있습니다.
-
절대 경로를 반환하지만 심볼릭 링크를 확인하지 않습니다.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에 오류가 발생합니다.
오래된 질문이지만 쉘 수준에서
전체 경로 이름
을 처리 하는 경우 훨씬 간단한 방법 이 있습니다 .
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를 수행하는 경우에는 쓸모가 없습니다.
내 최근 해결책은 다음과 같습니다.
pushd foo/bar/..
dir=`pwd`
popd
Tim Whitcomb의 답변을 바탕으로합니다.
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
.
정확히 대답은 아니지만 후속 질문 일 수도 있습니다 (원래 질문은 명시 적이 지 않음).
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
말이 많고 약간 늦었습니다. 오래된 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`
나는 파티에 늦었지만 다음과 같이 많은 스레드를 읽은 후에 만들어진 솔루션입니다.
resolve_dir() {
(builtin cd `dirname "${1/#~/$HOME}"`'/'`basename "${1/#~/$HOME}"` 2>/dev/null; if [ $? -eq 0 ]; then pwd; fi)
}
이것은 $ 1의 절대 경로를 해결하고 ~로 잘 플레이하고 경로에 symlinks를 유지하며 디렉토리 스택을 망칠 수 없습니다. 전체 경로를 반환하거나 존재하지 않는 경우 아무것도 반환하지 않습니다. $ 1은 디렉토리가 될 것으로 예상하고 그렇지 않으면 실패 할 것입니다.하지만 쉽게 확인할 수 있습니다.
GitHub에 배치 한 무료 Bash 라이브러리 제품인
를 무료로 사용해보십시오 . 철저하게 문서화되어 있으며 훌륭한 학습 도구를 만듭니다.로컬, 상대 및 절대 경로를 해결하고 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
}
It also contains functions to get_dirname, get_filename, get_ stemname and validate_path. Try it across platforms, and help to improve it.
Based on @Andre's answer, I might have a slightly better version, in case someone is after a loop-free, completely string-manipulation based solution. It is also useful for those who don't want to dereference any symlinks, which is the downside of using realpath
or readlink -f
.
It works on bash versions 3.2.25 and higher.
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
The problem with realpath
is that it is not available on BSD (or OSX for that matter). Here is a simple recipe extracted from a rather old (2009) article from Linux Journal, that is quite portable:
function normpath() {
# Remove all /./ sequences.
local path=${1//\/.\//\/}
# Remove dir/.. sequences.
while [[ $path =~ ([^/][^/]*/\.\./) ]]; do
path=${path/${BASH_REMATCH[0]}/}
done
echo $path
}
Notice this variant also does not require the path to exist.
Based on loveborg's excellent python snippet, I wrote this:
#!/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)
This works even if the file doesn't exist. It does require the directory containing the file to exist.
I needed a solution that would do all three:
- Work on a stock Mac.
realpath
andreadlink -f
are addons - Resolve symlinks
- Have error handling
None of the answers had both #1 and #2. I added #3 to save others any further yak-shaving.
#!/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")"
Here is a short test case with some twisted spaces in the paths to fully exercise the quoting
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 "
I know this is an ancient question. I'm still offering an alternative. Recently I met the same issue and found no existing and portable command to do that. So I wrote the following shell script which includes a function that can do the trick.
#! /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
I discovered today that you can use the stat
command to resolve paths.
So for a directory like "~/Documents":
You can run this:
stat -f %N ~/Documents
To get the full path:
/Users/me/Documents
For symlinks, you can use the %Y format option:
stat -f %Y example_symlink
Which might return a result like:
/usr/local/sbin/example_symlink
The formatting options might be different on other versions of *NIX but these worked for me on OSX.
A simple solution using node.js
:
#!/usr/bin/env node
process.stdout.write(require('path').resolve(process.argv[2]));
참고URL : https://stackoverflow.com/questions/284662/how-do-you-normalize-a-file-path-in-bash
'programing' 카테고리의 다른 글
Date 객체를 달력 객체로 변환 (0) | 2020.05.17 |
---|---|
Oracle SQL Developer에서 사용자 정의 날짜 시간 형식을 설정하는 방법 (0) | 2020.05.17 |
파이썬으로 UTF-8 파일에 쓰기 (0) | 2020.05.17 |
안드로이드에서 타원 크기는 무엇을 의미합니까? (0) | 2020.05.17 |
jquery에서 모든 확인란을 선택하십시오. (0) | 2020.05.17 |