Bash 스크립트에서 현재 디렉토리 이름 (전체 경로없이) 가져 오기


답변:


1115

기본 이름이 필요하지 않으며 특히 pwd를 실행하는 서브 쉘이 필요하지 않습니다 ( 추가적이고 값 비싼 포크 작업을 추가 함 ). 쉘은 매개 변수 확장을 사용하여 내부적 으로이 작업을 수행 할 수 있습니다 .

result=${PWD##*/}          # to assign to a variable

printf '%s\n' "${PWD##*/}" # to print to stdout
                           # ...more robust than echo for unusual names
                           #    (consider a directory named -e or -n)

printf '%q\n' "${PWD##*/}" # to print to stdout, quoted for use as shell input
                           # ...useful to make hidden characters readable.

다른 상황에서 (이 아닌 PWD디렉토리 이름을 가진 다른 변수) 에이 기술을 적용하는 경우 후행 슬래시를 잘라야 할 수도 있습니다. 아래는 bash의 extglob 지원 을 사용 하여 후행 슬래시가 여러 개인 경우에도 작동합니다.

dirname=/path/to/somewhere//
shopt -s extglob           # enable +(...) glob syntax
result=${dirname%%+(/)}    # trim however many trailing slashes exist
result=${result##*/}       # remove everything before the last / that still remains
printf '%s\n' "$result"

또는 extglob: 없이

dirname="/path/to/somewhere//"
result="${dirname%"${dirname##*[!/]}"}" # extglob-free multi-trailing-/ trim
result="${result##*/}"                  # remove everything before the last /

31
$ {PWD ## * /}와 $ PWD의 차이점은 무엇입니까?
Mr_Chimp

24
@Mr_Chimp 전자는 기본 디렉토리 만 제공하기 위해 나머지 디렉토리를 잘라내는 매개 변수 확장 조작입니다. 매개 변수 확장에 대한 설명서에 대한 답변에 링크가 있습니다. 궁금한 점이 있으면 언제든지 따르십시오.
Charles Duffy

24
@stefgosselin $PWD은 내장 bash 변수의 이름입니다. 모든 내장 변수 이름은 모두 대문자로되어 있습니다 (로컬 변수와 구별하기 위해 항상 소문자가 하나 이상 있어야 함). 평가 result=${PWD#*/}하지 않습니다/full/path/to/directory ; 대신 첫 번째 요소 만 제거하여 만듭니다 path/to/directory. 두 #문자를 사용하면 패턴이 욕심이되어 최대한 많은 문자가 일치합니다. 자세한 내용은 답변에 링크 된 매개 변수 확장 페이지를 읽으십시오.
Charles Duffy

5
심볼릭 링크를 통해 발생하는 합병증 , bash에 옵션 세트 가 있는지 여부 등으로 인해 출력 pwd값이 항상 값과 같지는 않습니다 . 이것은 자동 마운트 된 디렉토리를 처리 할 때 특히 골치 거리가되는데, 논리적 경로 대신 물리적 경로를 기록하면 사용되는 경우 자동 마운터가 자발적으로 디렉토리를 마운트 해제 할 수있는 경로가 생성됩니다. $PWDcd-o physical
Alex North-Keys

3
좋은! 누군가 나 같은 나이 든 Borne 쉘 남자를위한 책을 써야한다. 어쩌면 거기에 하나가 있습니까? 그것은 "우리는 다시 내 하루에, 오래된 SYS 같은 물건을 말하는 관리자 crotchity을 가질 수 shcsh당신이 전체 읽을 수 있었다 일할 수있는 백 스페이스 키를 원하는 경우 stty매뉴얼 페이지를, 우리는 그것을 좋아!"
레드 크리켓

335

basename프로그램을 사용하십시오 . 귀하의 경우 :

% basename "$PWD"
bin

20
이것이 basename프로그램 의 목적이 아닙니까? 따옴표가 누락 된 것 외에이 답변에 어떤 문제가 있습니까?
Nacht-복원 모니카

11
@Nacht는 basename참으로 올바른 일을 외부 프로그램이지만, 실행 어떤 일이 강타를위한 외부 프로그램은 즉시 사용 할 수있는 유일한 내장 기능이 바보 사용 (성능에 미치는 영향을 초래 fork(), execve(), wait()위해 등) 이유없이.
Charles Duffy

3
... 단, 슬래시가없는 문자열을 (으)로 변환하지 않는 기능이 있기 때문에 basename여기에 대한 나의 반대 의견 적용 되지 않습니다 . 따라서 외부 도구로 사용 하면 성능 오버 헤드가 발생하지만이를 보완하는 데 도움이되는 기능도 있습니다. dirnamedirname${PWD##*/}.dirname
Charles Duffy

4
@LouisMaddox, 약간의 kibitzing : function키워드는 표준화 된 구문에 값을 추가하지 않고 POSIX와 호환되지 않으며 따옴표가 없으면 디렉토리 이름에 공백이있는 버그가 발생합니다. wdexec() { "./$(basename "$PWD")"; }바람직한 대안이 될 수 있습니다.
Charles Duffy

28
사용하는 basename것이 덜 "효율적"입니다. 그러나 추악한 bash 구문에 비해 기억하기 쉽기 때문에 개발자 생산성 측면에서 효율적일 것입니다 . 기억이 나면 가십시오. 그렇지 않으면 basename잘 작동합니다. 누군가가 bash 스크립트의 "성능"을 향상시키고 더 효율적으로 만들어야 했습니까?
usr

139
$ echo "${PWD##*/}"

​​​​​


2
@jocap ... 에코의 사용이 인수를 인용하지 않고,이 점을 제외하고 잘못 . 디렉토리 이름에 공백이나 탭 문자가 여러 개인 경우 단일 공백으로 축소됩니다. 와일드 카드 문자가 있으면 확장됩니다. 올바른 사용법은입니다 echo "${PWD##*/}".
Charles Duffy

9
@jocap ... 또한 "echo"가 실제로 합법적 인 부분인지 확실하지 않습니다. 문제는 답변을 인쇄 하는 방법이 아니라 답변 을 얻는 방법이었습니다 . 예를 들어, 목표를 변수에 할당하는 것이 옳았 을 때 (불필요하고 비효율적 인 의미로) 잘못되었을 것입니다. name=${PWD##*/}name=$(echo "${PWD##*/}")
Charles Duffy

24

pwd와 basename의 조합을 사용할 수 있습니다. 예 :

#!/bin/bash

CURRENT=`pwd`
BASENAME=`basename "$CURRENT"`

echo "$BASENAME"

exit;

18
안돼 백틱은 서브 쉘 (따라서 포크 조작)을 작성합니다.이 경우에는 두 번 사용합니다 ! [스타일리쉬 한 퀴즈 임에도 불구하고 변수 이름은 환경으로 내보내거나 특별한 예약 된 경우가 아니라면 소문자 여야합니다].
Charles Duffy

11
그리고 두 번째 스타일의 퀴즈 백틱은 $ ()로 대체되어야합니다. 여전히 포크이지만 더 읽기 쉽고 더 적은 탈출이 필요합니다.
Jeremy Wall

1
일반적으로 환경 변수 (PATH, EDITOR, SHELL, ...) 및 내부 쉘 변수 (BASH_VERSION, RANDOM, ...)는 완전히 대문자로 표시됩니다. 다른 모든 변수 이름은 소문자 여야합니다. 변수 이름은 대소 문자를 구분하므로이 규칙은 실수로 환경 및 내부 변수를 재정의하지 않습니다.
Rany Albeg Wein

2
컨벤션에 따라 다릅니다. 모든 쉘 변수는 환경 변수 (쉘에 따라 다름)이며 모든 쉘 변수는 모두 대문자 여야한다고 주장 할 수 있습니다. 다른 사람은 범위를 기반으로 논쟁 할 수 있습니다-전역 변수는 모두 대문자이고 지역 변수는 소문자이며 모두 전역입니다. 그러나 다른 사람들은 모두 대문자로 변수를 만들면 쉘 스크립트를 버리는 명령과 대비가 더 좁아지고 소문자이지만 의미가있는 단어이기도합니다. 나는 그 주장들 중 어느 것에도 동의하거나 동의하지 않을 수도 있지만, 세 가지를 모두 사용하는 것을 보았다. :)
dannysauer 2016 년

17

grep은 어떻습니까 :

pwd | grep -o '[^/]*$'

색상 정보를 얻는 것처럼 보이지는 않지만 권장 pwd | xargs basename하지는 않습니다. 그다지 중요하지는 않지만 다른 대답은 환경에서 더 단순하고 일관성이 있습니다
davidhq

8

선택한 답변 (Charles Duffy)이 마음에 들지만 심볼릭 디렉토리에 있고 대상 디렉토리의 이름을 원할 경우주의하십시오. 불행히도 단일 매개 변수 확장 식으로 수행 할 수 있다고 생각하지 않습니다. 아마도 실수입니다. 이것은 작동해야합니다 :

target_PWD=$(readlink -f .)
echo ${target_PWD##*/}

이것을보기 위해 실험 :

cd foo
ln -s . bar
echo ${PWD##*/}

"바"보고서

DIRNAME

경로의 주요 디렉토리를 표시하려면 (/ usr / bin / dirname의 fork-exec가 발생하지 않음) :

echo ${target_PWD%/*}

예를 들어 foo / bar / baz-> foo / bar 변환


5
불행히도 readlink -fGNU 확장은 BSD (OS X 포함)에서 사용할 수 없습니다.
Xiong Chiamiov

8
echo "$PWD" | sed 's!.*/!!'

Bourne 쉘을 사용 중이거나 ${PWD##*/}사용할 수없는 경우


4
참고 ${PWD##*/}로 POSIX sh입니다. 모든 현대 / bin / sh (대시, 애쉬 등 포함)가이를 지원합니다. 최근 박스에서 실제 Bourne을 누르려면 약간 오래된 Solaris 시스템에 있어야합니다. 그 너머- echo "$PWD"; 따옴표를 생략하면 버그가 발생합니다 (디렉토리 이름에 공백, 와일드 카드 문자 등이있는 경우).
Charles Duffy

1
예, 오래된 Solaris 시스템을 사용하고있었습니다. 따옴표를 사용하도록 명령을 업데이트했습니다.
anomal

7

이 스레드는 훌륭합니다! 여기 또 다른 맛이 있습니다 :

pwd | awk -F / '{print $NF}'

5

놀랍게도 아무도 내장 bash 명령 만 사용하는이 대안을 언급하지 않았습니다.

i="$IFS";IFS='/';set -f;p=($PWD);set +f;IFS="$i";echo "${p[-1]}"

AS를 추가 보너스 당신은 쉽게 상위 디렉토리로의 이름을 얻을 수 있습니다 :

[ "${#p[@]}" -gt 1 ] && echo "${p[-2]}"

이것들은 Bash 4.3-alpha 이상에서 작동합니다.


놀랍게도? 농담이지만 ​​다른 사람들은 훨씬 짧고 기억하기 쉽습니다
codewandler

이것은 꽤 재밌다. 내 bash는 너무 나이,하지만 여기 테스트 할 수 jdoodle.com/test-bash-shell-script-online
스탠 Kurdziel

5

사용하다:

basename "$PWD"

또는

IFS=/ 
var=($PWD)
echo ${var[-1]} 

IFS (Internal Filename Separator)를 다시 공간으로 돌립니다.

IFS= 

IFS 뒤에 공백이 하나 있습니다.


4
basename $(pwd)

또는

echo "$(basename $(pwd))"

2
더 많은 따옴표가 필요 pwd합니다 basename. 그대로 전달되기 전에 출력 이 문자열 분할되고 glob-expanded됩니다 .
찰스 더피

따라서, basename "$(pwd)"- 그 단지에 비해 매우 비효율적이지만 basename "$PWD", 인 자체 매개 변수 확장을 사용하는 대신 호출에 비해 비효율적 basename전혀.
Charles Duffy

4

저처럼 기수 찾기를 위해 :

find $PWD -maxdepth 0 -printf "%f\n"

변경 $PWD"$PWD"제대로 특이한 디렉토리 이름을 처리 할 수 있습니다.
Charles Duffy

3

나는 보통 sh 스크립트에서 이것을 사용한다

SCRIPTSRC=`readlink -f "$0" || echo "$0"`
RUN_PATH=`dirname "${SCRIPTSRC}" || echo .`
echo "Running from ${RUN_PATH}"
...
cd ${RUN_PATH}/subfolder

이것을 사용하여 물건을 자동화 할 수 있습니다 ...


readlink: illegal option -- f usage: readlink [-n] [file ...]

2

정규식이있는 grep 아래도 작동합니다.

>pwd | grep -o "\w*-*$"

3
디렉토리 이름에 "-"문자가 포함되어 있으면 작동하지 않습니다.
daniula

1

그냥 사용하십시오 :

pwd | xargs basename

또는

basename "`pwd`"

2
이것은 모든면에서 Arkady가 이전에 제공 한 답변의 더 나쁜 버전입니다 ( stackoverflow.com/a/1371267/14122 ) : xargs디렉토리 이름에 문자 줄 바꿈 문자 또는 인용 부호가 포함되어 있고 두 번째 공식이 pwd명령을 호출하면 formultion이 비효율적이며 버그가 있습니다. 내장 변수 확장을 통해 동일한 결과를 검색하는 대신 서브 쉘에서.
찰스 더피

@CharlesDuffy 그럼에도 불구하고 그것은 질문에 대한 타당하고 실용적인 대답입니다.
bachph


0

/로 끝나는 접두사와 문자열에서 접미사 (문자열에있는 경우)를 삭제하고 결과를 표준 출력에 인쇄하는 basename 유틸리티를 사용할 수 있습니다.

$basename <path-of-directory>

0

나는 강하게 사용하는 것을 선호합니다 gbasenameGNU coreutils의 일부인을 하는 것이 좋습니다.


참고로, 우분투 배포판과 함께 제공되지 않습니다.
Katastic Voyage

@KatasticVoyage, 우분투에 있으며 방금 호출 basename됩니다. 일반적으로 gbasenameGNU가 아닌 기본 이름 으로 제공 되는 MacOS 및 기타 플랫폼 에서만 호출 됩니다.
Charles Duffy

-1

다음 명령은 현재 작업 디렉토리를 bash 스크립트로 인쇄합니다.

pushd .
CURRENT_DIR="`cd $1; pwd`"
popd
echo $CURRENT_DIR

2
(1) 인수 목록이 $1현재 작업 디렉토리를 포함 할 것인지 확실하지 않습니다 . (2) pushdpopd역 따옴표 안에 아무것도가 서브 쉘에서 수행되기 때문에 여기에 어떤 목적에 봉사하지 - 그것은 시작하는 부모 쉘의 디렉토리에 영향을 미치지 수 있습니다. (3) "$(cd "$1"; pwd)"공백이있는 디렉토리 이름에 비해 사용하기 가 더 읽기 쉽고 탄력적입니다.
Charles Duffy
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.