따옴표를 사용하거나 사용하지 않고 변수를 정의하는 것의 차이점은 무엇입니까? [복사]

따옴표를 사용하거나 사용하지 않고 변수를 정의하는 것의 차이점은 무엇입니까? [복사]

따옴표로 변수를 정의하는 경우:

TEMP="~/Dropbox"

그 다음에

ls $TEMP

작동하지 않습니다. 대신

echo $TEMP | ls

일하다.

동일한 결과를 얻으려면 다음과 같이 따옴표 없이 변수를 정의할 수도 있습니다.

TEMP=~/Dropbox

이렇게 하면 간단히 입력할 수 있습니다.

ls $TEMP

나는 그들 사이의 차이점에 대해 혼란스럽고 언제 어디서 이 두 정의를 각각 사용해야 하는지 알고 싶습니다.

답변1

TEMP="~/Dropbox"

위의 내용은 리터럴 물결표와 슬래시가 포함된 변수를 정의합니다. 따옴표로 묶여 있기 때문에 쉘은 ~/홈 디렉토리로 확장되지 않습니다. 관찰하다:

$ echo "quotes=~/" noquotes=~/
quotes=~/ noquotes=/home/john1024/

~/따라서 홈 디렉토리를 나타내 려면 ~/따옴표를 벗어나야 합니다. 다음은 작동합니다:

TEMP=~/"Dropbox"

~/따옴표로 묶으면 어떻게 되는지 생각해 봅시다 :

TEMP="~/Dropbox"
ls $TEMP

~/Dropbox위의 명령은 이름이 지정된 디렉터리에 있는 파일을 나타내는 파일을 찾습니다 . 이름이 지정된 디렉터리가 없을 가능성이 높으므로 "해당 파일이나 디렉터리가 없습니다."라는 오류 메시지가 반환됩니다.Dropbox~~ls

또한 아래 명령은 생각한 대로 작동하지 않습니다.

echo $TEMP | ls

ls표준 입력은 무시됩니다. bare ls명령은 해당 디렉터리가 무엇이든 현재 디렉터리의 파일만 나열합니다.

답변2

man bash하고 "물결표 확장"을 찾으십시오.

즉, 따옴표가 없는 물결표(~)는 사용자의 집으로 대체되며, 변수의 일부인 경우 더 이상 발생하지 않습니다.

$ T=~/Downloads
$ echo $T
/home/zstegi/Downloads

$ T="~/Downloads"
$ echo $T
~/Downloads

답변3

이 문제에는 여러 측면이 있습니다. 첫째, 인용된 대입문의 효과는 다음 두 가지 이유로 인용문이 없는 동일한 대입문과 다를 수 있습니다.

  1. 과제에 구분 기호가 포함된 경우통사론토큰(예: ;<>또는 공백)그런 다음 따옴표로 묶을 수 있으며, 따옴표가 없는 할당문은 마커로 구분됩니다.

    • 및 일부 다른 셸 에서 bash토큰은 배열 할당을 나타내는 ()데 사용되는 특수한 경우이지만 var=(...)배열 확장을 지원하지 않는 POSIX 셸에서는 동일한 구성이 따옴표 없이 구문 오류가 됩니다.

      (   spc=  sc=; echo "<$spc>:<$sc>"
          spc=' ' sc=\;; echo "<$spc>:<$sc>"
      )
      

      <>:<>
      < >:<;>
      
  2. 할당에 확장 표시가 포함된 경우 따옴표로 인해 확장이 발생하지 않을 수 있으며, 확장 표시가 없으면 확장이 발생할 수 있습니다.

    • 포함된 모든 토큰이내에확장 내용이 실제로 확장에서 할당된 변수로 전달되기 때문에 확장이 적용되지 않습니다.
    • 큰따옴표는 표현식의 쉘 확장 "에 사용할 수 없으므로 일반적으로 대입문에서는 부적합합니다. 단, 다음을 포함하는 표현식의 확장 $에는 사용할 수 있습니다.$그리고컨텍스트의 다른 쉘 태그에 대한 참조입니다.

      (   spc=\  sc=";" 
          tkns=$(printf "(<\n\'\t)>|")$spc$sc\"
          names=tkns$spc$"sc$spc$"spc
          printf ::$%s::\\n "$names" "$tkns"
      )
      

      ::$tkns $sc $spc::
      ::$(<
      \'  )>| ;"::
      

셸 토큰은 셸에서 매우 특수한 문자입니다. 이는 명령을 서로 구분하고 명령 단어에서 명령 인수까지 구분하는 문자입니다. 쉘 단어를 분리/결합하는 문자입니다. 쉘 태그는 쉘 문자입니다.통사론파서(또는어휘 분석기)쉘은 명령의 일부 확장을 고려할 기회를 갖기 전에 명령을 읽으면서 해당 작업을 찾아 수행합니다.

하지만 다른 캐릭터도 있어요거의껍질에 특별합니다. 이는 셸 매개변수 값에 포함된 문자와 같이 셸 확장에 영향을 주는 문자 $IFS는 물론, ?[*질문에서 언급한 대로 ~물결표와 같은 파일 이름 확장 메타 문자입니다.

특수한 경우 물결표를 제외하고 ~이러한 문자는 할당문과 아무 관련이 없습니다.문맥(대목록문맥)$IFS분할 및 파일 이름 확장자의 영향 을 받지 않습니다 . 따라서 변수 할당에서 발생하는 확장에는 명령 목록에서와 같이 리터럴 값 보호가 필요하지 않습니다.

그래서 다음은 작동합니다 ...

(meta=*?; meta=[$meta; echo "$meta")

[*?

그러나 물결표는 ~특별한 쉘 확장입니다. 확장 처리 alias는 내용이 항상 문자 그대로 확장된다는 점에서 매우 쉘과 유사합니다 . ~물결표와 확장 모두 - 확장을 나타내는 alias일반적인 달러 기호와 같습니다.$상황 - 예언제나파일 이름 확장자의 영향을 받지 않습니다 $IFS. 그러나 ~물결표는 거의 항상 인수로 확장되며 값이 <space>로 끝나는 다른 확장된 쉘 alias바로 뒤에 나오지 않는 한 쉘은 해당 컨텍스트에서 확장될 수 없다는 점에서 다릅니다 .alias

물결표 확장은 ~어떤 종류의 따옴표 안에서도 발생하지 않으며, 모든 측면에서 적절하게 구분되지 않거나 후행 컨텍스트 이름이 시스템 사용자와 쉘에서 이 사실을 제대로 인식할 수 없는 한 전혀 발생하지 않습니다.

그래서...

~some_user

...사용자의 홈 디렉토리로 확장됩니다.some_user쉘이 그러한 사용자가 존재한다는 것을 확인할 수 있으면 그렇지 않으면 전혀 확장되지 않습니다.

도착하다올바르게 정의됨물결표 확장의 경우 오른쪽에 있는 ~따옴표와 a를 제외하고 이미 언급한 쉘 태그 중 하나를 사용할 수 있습니다./목록맥락에서 또는컨텍스트는 /오른쪽 :이나 왼쪽, =할당문의 첫 번째 또는 :다른 어느 곳에나 있습니다.

후행 컨텍스트가 없고 ~물결표가 적절하게 구분된 경우 ~물결표는 쉘 변수의 현재 값으로 확장됩니다 $HOME. 이러한 구별은 물결표 확장을 논의할 때 종종 실수로 무시됩니다 ~. 쉘 변수는 다른 시간과 마찬가지로 언제든지 재할당하거나 재할당할 수 있으므로 사용자의 홈 디렉터리와 값이 $HOME동일할 필요는 없습니다. 실제로 언제$HOMEunset$HOME unset~, POSIX는 별도의 물결표 확장 동작을 유지합니다.명시되지 않은그러나 bash예를 들어 시스템에서 현재 사용자의 홈 디렉터리를 찾으려는 시도가 이루어집니다.

예를 들어:

HOME="

:~"::~//~ bash -c '
    printf "\t<%s>" ~/ ~mikeserv/
    HOME=; echo
    printf "\t<%s>" ~/ ~mikeserv/
    unset HOME; echo
    printf "\t<%s>" ~/ ~mikeserv/
'

    <

:~::/home/mikeserv//~/> </home/mikeserv/>
    </> </home/mikeserv/>
    </home/mikeserv/>   </home/mikeserv/>

관련 정보