Bash 변수를 사용할 때 $myvar과 "$myvar"의 차이점은 무엇입니까? (특정 이상한 행동)

Bash 변수를 사용할 때 $myvar과 "$myvar"의 차이점은 무엇입니까? (특정 이상한 행동)

일반적인 질문:

Bash에서는 변수를 myvar두 가지 방법으로 사용할 수 있다는 것을 알고 있습니다.

# Define a variable:
bash$ myvar="two words"

# Method one to dereference:
bash$ echo $myvar
two words

# Method two to dereference:
bash$ echo "$myvar"
two words

위의 경우 동작은 동일합니다. 이는 작동 방식 때문입니다 echo. 다른 Unix 유틸리티에서는 단어를 큰따옴표로 그룹화하는지 여부가 큰 차이를 만듭니다.

bash$ myfile="Cool Song.mp3"
bash$ rm "$myfile"            # Deletes "Cool Song.mp3".
bash$ rm $myfile              # Tries to delete "Cool" and "Song.mp3".

이 차이의 더 깊은 의미가 무엇인지 궁금합니다. 가장 중요한 것은 명령에 전달될 내용을 정확하게 보고 해당 내용이 올바르게 인용되었는지 확인하려면 어떻게 해야 합니까?

특정 홀수 예:

관찰된 동작으로 코드를 작성하겠습니다.

bash$ mydate="--date=format:\"%Y-%m-%d T%H\""
bash$ git log "$mydate"    # This works great.
bash$ git log $mydate
fatal: ambiguous argument 'T%H"': unknown revision or path not in the working tree.

왜 큰따옴표가 필요한가요? 큰따옴표 없이 변수를 역참조한 후 git-log에는 정확히 무엇이 표시됩니까?

하지만 이제 이것을 보세요:

bash$ nospace="--date=format:\"%Y-%m-%d\""
bash$ git log $nospace        # Now THIS works great.
bash$ git log "$nospace"      # This kind of works, here is a snippet:

# From git-log output:
Date:   "2018-04-12"

윽, 이제 인쇄된 출력물에 큰따옴표가 있는 이유는 무엇입니까? 큰 따옴표가 불필요한 경우 제거되지 않고 필요하지 않은 경우에만 리터럴 따옴표 문자로 해석되는 것처럼 보입니다.

Git이 인수로 전달되는 것은 무엇입니까?알아내는 방법을 알고 싶습니다.

문제를 더 복잡하게 만들기 위해 저는 argparse모든 인수를 인쇄하는 Python 스크립트를 작성했습니다(Bash가 해석한 대로, Bash가 인수의 일부라고 생각하는 큰따옴표 리터럴과 Bash로 그룹화되거나 그룹화되지 않은 단어를 사용). 적합하다고 생각함) Python argparse스크립트는 매우 합리적으로 작동합니다. 슬프게도 나는 argparseBash의 알려진 문제를 자동으로 수정하여 Bash가 전달하는 엉망인 내용을 모호하게 할 수 있다고 생각합니다. 그냥 추측일 뿐이라 잘 모르겠네요. 어쩌면 git-log가 Bash가 전달하는 내용을 비밀리에 망치고 있을 수도 있습니다.

아니면 무슨 일이 일어나고 있는지 전혀 모르는 것일 수도 있습니다.

감사해요.

편집됨 편집:대답이 나오기 전에 지금부터 말씀드리겠습니다. 나는 할 수 있다는 것을 알고 있습니다.아마도전체를 작은따옴표로 묶고 큰따옴표를 벗어나지 마세요. 이것은 실제로 git-log를 사용한 초기 문제에 대해 다소 더 잘 작동하지만 다른 상황에서 테스트했는데 거의 똑같이 예측할 수 없고 신뢰할 수 없습니다. 내부 변수를 인용하는 데 이상한 일이 벌어지고 있습니다. 나는 작은 따옴표로 인해 발생한 이상한 일들을 모두 게시하지 않을 것입니다.

편집 2 - 이것도 작동하지 않습니다.방금 이런 멋진 아이디어가 떠올랐지만 전혀 작동하지 않습니다.

bash$ mydate="--date=format:%Y-%m-%d\ T%H"
bash$ git log "$mydate"

# Git log output has this:
Date:   2018-04-12\ T23

그래서 그것을 감싸는 따옴표가 없습니다.하지만날짜 문자열에 리터럴 백슬래시 문자가 있습니다. 또한 git log $mydate변수에 백슬래시 공백이 있으면 따옴표 오류가 발생하지 않습니다.

답변1

다른 접근 방식:

를 실행할 때 git log --format="foo bar"해당 인용문은 git에 의해 해석되지 않습니다. 즉, 셸에 의해 제거됩니다(그리고 인용된 텍스트가 분할되지 않도록 보호합니다). 결과적으로 단일 인수가 생성됩니다.

  • --format=foo bar

그러나 인용되지 않은 경우변수확장되면 결과는 단어 분할을 거치지만~ 아니다인용 해제를 통해. 따라서 변수에 가 포함되어 있으면 --format="foo bar"다음 인수로 확장됩니다.

  • --format="foo
  • bar"

이는 다음을 사용하여 확인할 수 있습니다.

  • printf '%s\n' $변수

...수신된 인수를 인쇄하는 간단한 스크립트도 마찬가지입니다.

  • #!/usr/bin/env 펄
    $i에 대해 (0..$#ARGV) {
        인쇄 ($i+1)." = ".$ARGV[$i]."\n";
    }
    
  • #!/usr/bin/env python3
    수입 시스템
    i의 경우 열거형(sys.argv)의 인수:
        인쇄(i, "=", 인수)
    

bash를 항상 사용할 수 있는 경우 선호되는 해결 방법은 다음을 사용하는 것입니다.정렬변수:

myvar=( --format="foo bar" )

이를 통해 일반적인 구문 분석은 확장 중이 아닌 할당 중에 수행됩니다. 이 구문을 사용하여 변수의 내용을 확장하고 각 요소는 자체 인수를 얻습니다.

git log "${myvar[@]}"

답변2

원래 명령이 작동하지 않는 이유는 무엇입니까?

bash$ mydate="--date=format:\"%Y-%m-%d T%H\""
bash$ git log "$mydate"    # This works great.
bash$ git log $mydate
fatal: ambiguous argument 'T%H"': unknown revision or path not in the working tree.

물어:

왜 큰따옴표가 필요한가요? 큰따옴표 없이 변수를 역참조한 후 git-log에는 정확히 무엇이 표시됩니까?

주위에 큰따옴표를 사용하지 않으면 $mydate변수가 그대로 확장되고 쉘 라인은 실행되기 전에 다음과 같습니다.

git log --date=format:"%Y-%m-%d T%H"
                      ^————————————^—————— literal quotes

여기에서는 \"변수 할당에 를 사용하여 (불필요하게) 리터럴 인용문을 추가했습니다.

명령이 내려지기 때문에단어 분리, 및 의 git세 가지 인수를 받게 되므로 이름 이 지정된 커밋이나 개체를 찾을 수 없다고 불평합니다 .log--date-format:"%Y-%m%-dT%H"T%H"


올바른 접근 방식은 무엇입니까?

인수를 함께 유지하려면 해당 인수에 공백이 포함되어 있으면 인수를 따옴표로 묶어야 합니다.일반적으로 변수는 항상 큰따옴표로 묶습니다.

변수 내부에 공백이 있어도 작동합니다.

mydate="--date=format:%Y-%m-%d T%H"
git log "$mydate"

이제 원래 지정한 공간을 포함하여 gitwill 의 세 번째 인수 는 입니다. $mydate모든 따옴표는 에 전달되기 전에 쉘에 의해 제거됩니다 git.

단순히 추가 인용이 필요하지 않습니다. 원하는 것이 git하나의 인수만 보는 것이라면 변수를 전달할 때 해당 인수를 따옴표로 묶으십시오 "$mydate".


또한 다음과 같이 질문합니다.

bash$ nospace="--date=format:\"%Y-%m-%d\""
bash$ git log $nospace        # Now THIS works great.
bash$ git log "$nospace"      # This kind of works, here is a snippet:

# From git-log output:
Date:   "2018-04-12"

귀하의 질문:

윽, 이제 인쇄된 출력물에 큰따옴표가 있는 이유는 무엇입니까?

당신이 다시 포함했기 때문에오자예를 들어, 실제 명령에서 변수를 인용하는 것을 잊어버린 경우 "실제" 인용 부호로 바뀌게 됩니다. 쉘 명령에서 인용되지 않은 변수를 사용하는 것은 일반적으로 문제를 일으키기 때문에 "잊으십시오"라고 말합니다. 여기서는 처음에 변수를 지정하는 동안 발생한 오류를 되돌리는 것입니다.

추신: 이것이 모두 혼란스럽다는 것을 알고 있지만 그것은 Bash이고 몇 가지 명확한 규칙을 따릅니다. 여기에는 버그가 없습니다. ㅏ관련 에세이Bash의 공백 처리 문제를 다루기 때문에 Shell의 파일 이름에 대한 정보도 매우 공개적입니다.

관련 정보