불행히도 둘 다 단점이 있습니다.
둘 다 POSIX에 필요하므로 이들 간의 차이점은 이식성 문제 ¹가 아닙니다.
유틸리티를 사용하는 일반적인 방법은
base=$(basename -- "$filename")
dir=$(dirname -- "$filename")
--
파일 이름이 대시로 시작하는 경우 와 같이 변수 대체는 항상 따옴표로 묶고 명령 뒤에서 도 따옴표를 사용하십시오 (그렇지 않으면 명령이 파일 이름을 옵션으로 해석 함). 한 가지 경우에 여전히 실패하지만, 드물지만 악의적 인 사용자에 의해 강제 될 수 있습니다. 명령 대체는 후행 줄 바꿈을 제거합니다. 그래서 파일 이름이 호출되면 foo/bar
다음 base
에 설정됩니다 bar
대신 bar
. 해결 방법은 줄 바꿈이 아닌 문자를 추가하고 명령 대체 후 제거하는 것입니다.
base=$(basename -- "$filename"; echo .); base=${base%.}
dir=$(dirname -- "$filename"; echo .); dir=${dir%.}
매개 변수 대체를 사용하면 이상한 문자의 확장과 관련된 대소 문자가 발생하지 않지만 슬래시 문자에는 여러 가지 어려움이 있습니다. 전혀 중요하지 않은 한 가지는 디렉토리 부분을 계산하는 데없는 경우 다른 코드가 필요하다는 것입니다 /
.
base="${filename##*/}"
case "$filename" in
*/*) dirname="${filename%/*}";;
*) dirname=".";;
esac
가장 중요한 경우는 슬래시가있는 경우입니다 (모든 슬래시 인 루트 디렉토리의 경우 포함). basename
과 dirname
그들의 일을하기 전에 명령이 슬래쉬를 벗겨. POSIX 구문을 고수하면 후행 슬래시를 한 번에 제거 할 수는 없지만 두 단계로 수행 할 수 있습니다. 입력이 슬래시만으로 구성된 경우를 처리해야합니다.
case "$filename" in
*/*[!/]*)
trail=${filename##*[!/]}; filename=${filename%%"$trail"}
base=${filename##*/}
dir=${filename%/*};;
*[!/]*)
trail=${filename##*[!/]}
base=${filename%%"$trail"}
dir=".";;
*) base="/"; dir="/";;
esac
에지가 아닌 것을 알고 있다면 (예 : find
시작점 이외의 결과는 항상 디렉토리 부분을 포함하고 후행이 없음 /
) 매개 변수 확장 문자열 조작은 간단합니다. 모든 엣지 케이스에 대처해야하는 경우 유틸리티를 사용하기가 쉽지만 느립니다.
때때로, 당신은 foo/
처럼 foo/.
보다는 대우하고 싶을 수도 있습니다 foo
. 당신이 디렉토리 엔트리에 작용하는 경우 다음 foo/
에 해당 있어야하는데 foo/.
,하지 foo
; 이것은 foo
디렉토리에 foo
대한 심볼릭 링크 일 때 차이를 만듭니다. 심볼릭 링크를 foo/
의미하고 대상 디렉토리를 의미합니다. 이 경우, 슬래시가있는 경로의 기본 이름은 유리 .
하며 경로는 고유 한 이름 일 수 있습니다.
case "$filename" in
*/) base="."; dir="$filename";;
*/*) base="${filename##*/}"; dir="${filename%"$base"}";;
*) base="$filename"; dir=".";;
esac
빠르고 안정적인 방법은 zsh를 기록 수정 자 와 함께 사용하는 것입니다 (먼저 유틸리티와 같이 후행 슬래시를 제거합니다).
dir=$filename:h base=$filename:t
¹ 당신이 솔라리스 10 세의 같은 사전 POSIX 쉘을 사용하지 않는 /bin/sh
(매개 변수 확장 문자열 조작이 여전히 생산 시스템에 기능 부족 -하지만 항상 POSIX라는 쉘을 거기에 sh
설치 만 그건 /usr/xpg4/bin/sh
아니고 /bin/sh
).
² 예를 들어 foo
, 파일 업로드 서비스에 호출 된 파일을 보호하지 않는 파일을 제출 한 다음 삭제하고 foo
대신 삭제하십시오.
base=$(basename -- "$filename"; echo .); base=${base%.}; dir=$(dirname -- "$filename"; echo .); dir=${dir%.}
? 나는주의 깊게 읽고 있었고, 당신이 어떤 결점을 언급했는지 눈치 채지 못했습니다.