shellcheck는 basename을 사용하지 말라고 조언하고 있습니다: 왜 그렇습니까?

shellcheck는 basename을 사용하지 말라고 조언하고 있습니다: 왜 그렇습니까?

나는 노력하고있다쉘체크.

나한테도 그런 게 있는데

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##*/}, 이 방법은 더 쉽지만 그 자체로 버그가 있습니다. 특히 $fileis /또는 인 경우에는 잘못된 것입니다 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에게 감사 - 수정됨) basenamereadlink보안이 중요해지면(경로 보안 필요) 이식성 문제를 일으킬 수 있습니다. 많은 시스템(예: Fedora Linux)은 에 배치하는 /bin반면 다른 시스템(예: Mac OSX)은 에 배치합니다 /usr/bin. 그런 다음 Windows에는 cygwin, msys 등과 같은 Bash가 있습니다. 가능하다면 항상 순수한 Bash를 유지하는 것이 좋습니다.(@Marco 댓글 기준)

그런데, shellcheck에 대한 포인터를 알려주셔서 감사합니다. 이전에는 본 적이 없습니다.

관련 정보