Programing

파일의 절대 경로를 인쇄하는 bash / fish 명령

lottogame 2020. 2. 23. 11:32
반응형

파일의 절대 경로를 인쇄하는 bash / fish 명령


질문 : 공급하는 파일의 절대 경로를 인쇄하는 간단한 sh / bash / zsh / fish / ... 명령이 있습니까?

사용 사례 : 나는 디렉토리에 /a/b있고 c다른 프로그램에 쉽게 붙여 넣을 수 있도록 명령 줄에 파일의 전체 경로를 인쇄하고 싶습니다 /a/b/c. 간단하지만 아직이 작은 프로그램은 긴 경로를 처리 할 때 5 초 정도 절약 할 수 있습니다. 결국 추가됩니다. 이를 위해 표준 유틸리티를 찾을 수 없다는 사실에 놀랐습니다.

다음은 샘플 구현, abspath.py입니다.

#!/usr/bin/python
# Author: Diggory Hardy <diggory.hardy@gmail.com>
# Licence: public domain
# Purpose: print the absolute path of all input paths

import sys
import os.path
if len(sys.argv)>1:
    for i in range(1,len(sys.argv)):
        print os.path.abspath( sys.argv[i] )
    sys.exit(0)
else:
    print >> sys.stderr, "Usage: ",sys.argv[0]," PATH."
    sys.exit(1)

시도하십시오 realpath.

$ realpath example.txt
/home/username/example.txt

다음 readlink은 심볼릭 링크를 해결할 것입니다.

readlink -e /foo/bar/baz

#! /bin/sh
echo "$(cd "$(dirname "$1")"; pwd -P)/$(basename "$1")"

잊어 readlinkrealpath이는 또는 시스템에 설치 될 수도 있고 그렇지 않을 수도있다.

의 dogbane의 대답을 확장 하면 함수로 표현됩니다.

#!/bin/bash
get_abs_filename() {
  # $1 : relative filename
  echo "$(cd "$(dirname "$1")" && pwd)/$(basename "$1")"
}

그런 다음 다음과 같이 사용할 수 있습니다.

myabsfile=$(get_abs_filename "../../foo/bar/file.txt")

어떻게 그리고 왜 작동합니까?

이 솔루션은 Bash 내장 pwd명령이 인수없이 호출 될 때 현재 디렉토리의 절대 경로를 인쇄 한다는 사실을 이용합니다 .

이 솔루션을 왜 좋아합니까?

그것은 휴대용이고 어느 쪽도 필요로하지 않는다 readlink또는 realpath종종 기본에 존재하지 않는이 주어진 리눅스 / 유닉스 배포판의 설치합니다.

dir이 없으면 어떻게됩니까?

위에서 주어진 것처럼 주어진 디렉토리 경로가 존재하지 않으면 함수는 실패하고 stderr에 인쇄합니다. 이것은 당신이 원하는 것이 아닐 수도 있습니다. 해당 상황을 처리하기 위해 기능을 확장 할 수 있습니다.

#!/bin/bash
get_abs_filename() {
  # $1 : relative filename
  if [ -d "$(dirname "$1")" ]; then
    echo "$(cd "$(dirname "$1")" && pwd)/$(basename "$1")"
  fi
}

이제 부모 디렉토리가 존재하지 않으면 빈 문자열을 반환합니다.

후행 '..'또는 '.'를 어떻게 처리합니까? 입력?

이 경우에는 절대 경로를 제공하지만 최소한의 경로는 제공하지 않습니다. 다음과 같이 보일 것입니다 :

/Users/bob/Documents/..

'..'을 해결하려면 다음과 같이 스크립트를 작성해야합니다.

get_abs_filename() {
  # $1 : relative filename
  filename=$1
  parentdir=$(dirname "${filename}")

  if [ -d "${filename}" ]; then
      echo "$(cd "${filename}" && pwd)"
  elif [ -d "${parentdir}" ]; then
    echo "$(cd "${parentdir}" && pwd)/$(basename "${filename}")"
  fi
}

$ readlink -m FILE
/path/to/FILE

파일이 존재하지 않더라도 작동하기 때문에 readlink -e FILE또는 보다 좋습니다 realpath.


절대 경로 변환기 쉘 기능에 대한 상대 경로

  • 유틸리티가 필요하지 않습니다 (단지 cdpwd)
  • 디렉토리와 파일에 사용
  • 손잡이 ...
  • dir 또는 filename에서 공백을 처리합니다.
  • 파일 또는 디렉토리가 있어야합니다.
  • 주어진 경로에 아무것도 없으면 아무것도 반환하지 않습니다.
  • 절대 경로를 입력으로 처리 (기본적으로 통과)

암호:

function abspath() {
    # generate absolute path from relative path
    # $1     : relative filename
    # return : absolute path
    if [ -d "$1" ]; then
        # dir
        (cd "$1"; pwd)
    elif [ -f "$1" ]; then
        # file
        if [[ $1 = /* ]]; then
            echo "$1"
        elif [[ $1 == */* ]]; then
            echo "$(cd "${1%/*}"; pwd)/${1##*/}"
        else
            echo "$(pwd)/$1"
        fi
    fi
}

견본:

# assume inside /parent/cur
abspath file.txt        => /parent/cur/file.txt
abspath .               => /parent/cur
abspath ..              => /parent
abspath ../dir/file.txt => /parent/dir/file.txt
abspath ../dir/../dir   => /parent/dir          # anything cd can handle
abspath doesnotexist    =>                      # empty result if file/dir does not exist
abspath /file.txt       => /file.txt            # handle absolute path input

참고 : 이것은 nolan6000bsingh 의 답변 기반으로 하지만 파일 케이스를 수정합니다.

또한 원래 질문은 기존 명령 줄 유틸리티에 대한 것임을 이해합니다. 그러나 이것이 최소한의 종속성을 갖고 싶어하는 쉘 스크립트를 포함하여 스택 오버 플로우에 대한 질문 인 것처럼 보이기 때문에이 스크립트 솔루션을 여기에 배치하여 나중에 찾을 수 있습니다 :)


find명령이 도움 될 수 있습니다

find $PWD -name ex*
find $PWD -name example.log

패턴과 일치하는 이름으로 현재 디렉토리의 내부 또는 아래에있는 모든 파일을 나열합니다. 몇 가지 결과 만 얻는다면 단순화 할 수 있습니다 (예 : 파일이 적은 트리 하단 근처의 디렉토리).

find $PWD

다른 유틸리티는 언급하지 않은 Solaris 10에서 이것을 사용합니다.


readlink 또는 realpath 유틸리티가 없다면 bash 및 zsh에서 작동하는 다음 기능을 사용할 수 있습니다 (나머지에 대해서는 확실하지 않음).

abspath () { case "$1" in /*)printf "%s\n" "$1";; *)printf "%s\n" "$PWD/$1";; esac; }

이것은 존재하지 않는 파일에서도 작동합니다 (python 기능과 마찬가지로 os.path.abspath).

불행히도 abspath ./../somefile점을 제거하지 않습니다.


다음은 컴팩트 함을 좋아하는 zsh 전용 함수입니다. 'A'확장 수정자를 사용합니다 (zshexpn (1) 참조).

realpath() { for f in "$@"; do echo ${f}(:A); done }

일반적으로 파일에 대한 absolute path 내용은 없습니다 (이 내용은 일반적으로 둘 이상이있을 수 있으므로 정관사를 사용 하는 것이 적절하지 않음을 의미합니다). absolute path"/"루트에서 시작하는 어떤 경로와 독립적으로 작업 디렉토리의 모호성없이 파일을 지정합니다. (예를 들어 대한 참조 위키 피 디아 ).

A relative path는 다른 디렉토리에서 시작하여 해석되는 경로입니다. relative path응용 프로그램에서 조작 하는 경우 작업 디렉토리 일 수 있습니다 (필수는 아님). 디렉토리의 심볼릭 링크에있는 경우 일반적으로 해당 디렉토리와 관련이 있습니다 (사용자는 다른 용도를 염두에 둘 수 있음).

따라서 절대 경로는 루트 디렉토리에 상대적인 경로 일뿐입니다.

경로 (절대 또는 상대)는 기호 링크를 포함하거나 포함하지 않을 수 있습니다. 그렇지 않은 경우 연결 구조의 변경에도 다소 영향을 미치지 않지만 반드시 필요하거나 바람직하지는 않습니다. 어떤 사람들은 모든 상징적 연결이 해결 된, 즉 그들이 연결되는 경로로 대체 된 canonical path(또는 canonical file name또는 resolved path)을 호출 absolute path합니다. 명령 realpathreadlink둘 다 정식 경로를 찾지 만 realpath심볼릭 링크를 해결하지 않고 절대 경로를 얻는 옵션 있습니다 (몇 가지 다른 옵션과 함께 절대 경로 또는 일부 디렉토리에 상대적인 경로를 얻는 다른 옵션과 함께).

이를 위해서는 몇 가지 언급이 필요합니다.

  1. 심볼릭 링크는 링크되어야 할 것이 이미 생성 된 경우에만 해결할 수 있으며, 반드시 그런 것은 아닙니다. 명령 realpathreadlink이를 설명하는 옵션이 있습니다.
  2. 경로의 디렉토리는 나중에 기호 링크가 될 수 있으며, 이는 경로가 더 이상 존재하지 않음을 의미합니다 canonical. 따라서 개념은 시간 (또는 환경)에 따라 다릅니다.
  3. 이상적인 경우에도 모든 심볼릭 링크를 확인할 수있는 canonical path경우 두 가지 이유로 파일에 둘 이상이 있을 수 있습니다 .
    • 파일이 포함 된 파티션이 ro여러 마운트 지점에서 동시에 마운트되었을 수 있습니다 ( ).
    • 파일에 대한 하드 링크가있을 수 있습니다. 이는 파일이 여러 다른 디렉토리에 존재한다는 것을 의미합니다.

따라서을 훨씬 더 제한적으로 정의하더라도 canonical path파일에 대한 몇 가지 정식 경로가있을 수 있습니다. 이는 또한 한정자 canonical가 일반적으로 고유성 개념을 암시하기 때문에 다소 부적합하다는 것을 의미합니다.

이것은 Bash의 다른 유사한 질문에 대한 답변에서 주제에 대한 간단한 토론을 확장합니다 .

내 결론은 realpath보다 나은 디자인과 유연성보다 낫습니다 readlink. 이를 사용 readlink하지 않는 유일한 방법은 realpath심볼릭 링크의 값을 반환하는 옵션이없는 호출입니다.


dogbane 대답 에 오는 것을 설명과 :

#! /bin/sh
echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"

설명:

  1. 이 스크립트는 상대 경로를 인수로 얻습니다. "$1"
  2. 그런 다음 해당 경로의 dirname 부분을 얻습니다 (dir 또는 file을이 스크립트에 전달할 수 있음).dirname "$1"
  3. 그런 다음 cd "$(dirname "$1")이 상대 디렉토리로 들어가서 pwd쉘 명령 을 실행하여 절대 경로를 얻습니다.
  4. 그런 다음 절대 경로에 기본 이름추가 합니다.$(basename "$1")
  5. 마지막 단계는 우리로 echo그것을

디렉토리 dirname가 트립 ../되고를 반환합니다 ./.

nolan6000의 기능 을 수정하여 다음을 해결할 수 있습니다.

get_abs_filename() {
  # $1 : relative filename
  if [ -d "${1%/*}" ]; then
    echo "$(cd ${1%/*}; pwd)/${1##*/}"
  fi
}

이것은 질문에 대한 답변이 아니라 스크립팅을하는 사람들을위한 것입니다.

echo `cd "$1" 2>/dev/null&&pwd||(cd "$(dirname "$1")";pwd|sed "s|/*\$|/${1##*/}|")`

/ .. ./ 등을 올바르게 처리합니다. 나는 또한 OSX에서 일하는 것 같다


내 시스템에 다음 스크립트를 배치했으며 현재 디렉토리의 파일에 대한 전체 경로를 빠르게 잡고 싶을 때 bash 별칭이라고합니다.

#!/bin/bash
/usr/bin/find "$PWD" -maxdepth 1 -mindepth 1 -name "$1"

이유는 확실하지 않지만, 스크립트 "$ PWD"에 의해 호출 될 때 OS X에서 절대 경로로 확장됩니다. find 명령이 명령 행에서 호출 될 때 호출되지 않습니다. 그러나 그것은 내가 원하는 것을한다.


#! /bin/bash

file="$@"
realpath "$file" 2>/dev/null || eval realpath $(echo $file | sed 's/ /\\ /g')

이것은 단점을 보완 realpath하여 쉘 스크립트에 저장합니다 fullpath. 이제 전화 할 수 있습니다 :

$ cd && touch a\ a && rm A 2>/dev/null 
$ fullpath "a a"
/home/user/a a
$ fullpath ~/a\ a
/home/user/a a
$ fullpath A
A: No such file or directory.

루비 에서 절대 경로를 얻는 대안 :

realpath() {ruby -e "require 'Pathname'; puts Pathname.new('$1').realpath.to_s";}

인수가없는 인수 (현재 폴더)와 상대 및 절대 파일 또는 폴더 경로가 없습니다.


얘들 아 나는 그것이 오래된 실이라는 것을 알고 있지만 나처럼 이것을 방문한 다른 사람을 참조하기 위해 이것을 게시하고 있습니다. 질문을 올바르게 이해하면 locate $filename명령을 생각합니다 . 제공된 파일의 절대 경로를 표시하지만 존재하는 경우에만 표시합니다.

참고 URL : https://stackoverflow.com/questions/3915040/bash-fish-command-to-print-absolute-path-to-a-file



반응형