나는 노력하고있다쉘체크.
나한테도 그런 게 있는데
basename "${OPENSSL}"
그리고 나는 다음과 같은 제안을 받았습니다
Use parameter expansion instead, such as ${var##*/}.
실무적인 측면에서는 별 차이가 없다고 봅니다
$ export OPENSSL=/opt/local/bin/openssl
$ basename ${OPENSSL}
openssl
$ echo ${OPENSSL##*/}
openssl
basename
에 있기 때문에POSIX 사양, 이것이 모범 사례가 되어야 할 이유가 없습니다. 힌트가 있나요?
답변1
효율성에 관한 것이 아니라 정확성에 관한 것입니다. basename
인쇄할 파일 이름을 구분하기 위해 개행 문자를 사용합니다. 일반적인 경우 하나의 파일 이름만 전달하면 출력에 줄 바꿈이 추가됩니다. 파일 이름 자체에 개행 문자가 포함될 수 있으므로 이러한 파일 이름을 올바르게 처리하기가 어렵습니다.
basename
사람들이 일반적으로 다음과 같이 사용한다는 사실로 인해 더욱 복잡해졌습니다 "$(basename "$file")"
. $(command)
스트립이 있기 때문에 상황이 더욱 어려워집니다.모두.command
$file
개행 문자로 끝나는 가능성이 낮은 경우를 생각해 보세요 . 그런 다음 basename
추가 줄 바꿈을 추가하지만 "$(basename "$file")"
제거됩니다.둘 다개행으로 인해 잘못된 파일 이름이 남게 됩니다.
또 다른 문제는 (대시, 마이너스라고도 함) 로 시작 basename
하면 옵션으로 해석된다는 것입니다. 이것은 수정하기 쉽습니다:$file
-
$(basename -- "$file")
강력한 사용 방법은 basename
다음과 같습니다.
# A file with three trailing newlines.
file=$'/tmp/evil\n\n\n'
# Add an 'x' so we can tell where $file's newlines end and basename's begin.
file_x="$(basename -- "$file"; printf x)"
# Strip off two trailing characters: the 'x' added by us and the newline added by basename.
base="${file_x%??}"
대안은 을 사용하는 것인데 ${file##*/}
, 이 방법은 더 쉽지만 그 자체로 버그가 있습니다. 특히 $file
is /
또는 인 경우에는 잘못된 것입니다 foo/
.
답변2
shellcheck
' 의 관련 줄소스 코드이다:
checkNeedlessCommands (T_SimpleCommand id _ (w:_)) | w `isCommand` "dirname" =
style id "Use parameter expansion instead, such as ${var%/*}."
checkNeedlessCommands (T_SimpleCommand id _ (w:_)) | w `isCommand` "basename" =
style id "Use parameter expansion instead, such as ${var##*/}."
checkNeedlessCommands _ = return ()
명시적으로 제공된 설명은 없지만 함수 이름( checkNeedlessCommands
)을 기반으로 보면 @jordanm이 꽤 맞는 것처럼 보이며 새 프로세스를 포크하지 말 것을 제안합니다.
답변3
dirname
, 등(@Marco에게 감사 - 수정됨) basename
은 readlink
보안이 중요해지면(경로 보안 필요) 이식성 문제를 일으킬 수 있습니다. 많은 시스템(예: Fedora Linux)은 에 배치하는 /bin
반면 다른 시스템(예: Mac OSX)은 에 배치합니다 /usr/bin
. 그런 다음 Windows에는 cygwin, msys 등과 같은 Bash가 있습니다. 가능하다면 항상 순수한 Bash를 유지하는 것이 좋습니다.(@Marco 댓글 기준)
그런데, shellcheck에 대한 포인터를 알려주셔서 감사합니다. 이전에는 본 적이 없습니다.