큰따옴표로 묶인 문자열에서 변수 확장 후의 바이트가 이전 바이트를 덮어쓰는 이유는 무엇입니까?

큰따옴표로 묶인 문자열에서 변수 확장 후의 바이트가 이전 바이트를 덮어쓰는 이유는 무엇입니까?

일부 소프트웨어의 최신 버전을 다운로드하기 위해 쉘 스크립트를 작성 중입니다. 출력을 구문 분석한 후 curl정확한 버전 문자열을 찾기 위해 몇 가지 단계를 거쳤습니다(이 글을 쓰는 시점에서 0.65.3).

(아래의 모든 코드 예제에서 >이것은 내 프롬프트입니다. Bash 3.2 또는 Zsh의 출력은 접두사가 없는 행에 있습니다 >.)

> url="https://github.com/gohugoio/hugo/releases/latest"
> latest=$(curl --silent --head "$url" | grep Location)
> tag=$(echo "$latest" | cut -d'/' -f8)
> version=$(echo "${tag//v}")
> echo "hugo_${version}_Linux-64bit.tar.gz"
_Linux-64bit.tar.gz 

내가 예상하는 출력은 이지만 hugo_0.65.3_Linux-64bit.tar.gz따옴표 붙은 문자열이 포함된 호출의 출력에서는 echo이후 바이트가 ${version}따옴표 붙은 문자열의 시작 부분에 있는 바이트를 덮어쓰는 데 사용된 것으로 보입니다.

여기서는 무슨 일이 일어나고 있는지 설명하기 위해 두 개의 서로 다른 인용 문자열을 사용하고 있습니다.

> echo "hugo_${version}test"
test_0.65.3
> echo "hugo_${version}lorem ipsum dolor sit amet"
lorem ipsum dolor sit amet

나도 같은 결과를 얻습니다사고이렇게 하면 결과는 다음과 같습니다.

> version=$(echo "${tag:1}")
> echo "hugo_${version}_Linux-64bit.tar.gz"
_Linux-64bit.tar.gz 

하지만 이해한다예상되는이렇게 하면 결과는 다음과 같습니다.

> version=0.65.3
hugo_0.65.3_Linux-64bit.tar.gz

마지막 결과가 필요한 것이지만, 물론 스크립트를 동적이 아닌 정적으로 만들어 주므로 나에게는 별로 유용하지 않습니다. $version스크립트의 값을 하드코딩 하지 않고 어떻게 원하는 결과를 얻을 수 있나요 ?

답변1

반환된 줄은 curl캐리지 리턴 및 줄 바꿈으로 끝납니다. (MS-dos 줄 끝). Unix 도구는 개행 문자를 제거하지만 끝에 캐리지 리턴이 남습니다.

다음에 설명된 오류를 방지하려면 이 줄을 수정하여 사용 dos2unix하고 매개변수를 로 인용하세요.echo배쉬 트랩 #14):

version="$(echo "${tag//v}" | dos2unix)"

...또는 쉘의 내장 구문을 사용하여 실행합니다.둘 다지금 변경:

version=${tag//[$'v\r']/}

dos2unix실제로 몇 가지 다른 변경 사항이 적용되었습니다(예: UNIX에서는 필요하지만 DOS에서는 필요하지 않은 텍스트의 마지막 줄 뒤에 후행 줄 바꿈을 추가하는 등). 그러나 이와 같은 단일 줄 문자열의 경우 이러한 변경 사항 중 어느 것도 중요하지 않습니다.

답변2

Ctrl-Alt-Delor~의답변이 동작이 나타나는 이유를 설명하십시오. 그러나 기본 목표를 달성하려면 다음을 사용하는 것이 좋습니다.GitHub API"최신" 리디렉션을 해석하는 대신:

version=$(curl https://api.github.com/repos/gohugoio/hugo/releases/latest | jq -r '.tag_name | ltrimstr("v")')

이는 API에 최신 Hugo 버전을 요청하고 다음을 사용하여 태그 이름을 추출합니다.jq, 선행 "v"를 제거합니다.

이상적으로는 반환된 JSON에서 자산 이름과 URL을 추출할 수도 있습니다.

관련 정보