인용 부호“$ ()”가있는 변수


12

나는이 스크립트를 썼다 :

#!/bin/bash
while [ true ] 
do
    currentoutput="$(lsusb)"
    if [ "$currentoutput" != "$lastoutput" ]
    then
        echo "" date and Time >> test.log
        date +%x_r >> test.log
        lastoutput="$(lsusb)"
        lsusb >> test.log
    fi
    sleep 5
done

나는 빨리 배우려고하는 초보자이며 변수의 따옴표 에 대한 질문을 받았습니다 .

$ () 사이에 변수를 넣으면 얻을 수 있지만 명령문 에 따옴표가 필요한 이유는 if무엇입니까? 중첩 된 명령을 작성합니까?


5
참고 while [ true ]무한 루프를 생산하지만, 아마도하지 않는 이유 당신이하지 생각합니까; while [ false ] 또한 단일 인수를 사용 [ ... ]하면 인수가 비어 있지 않은 문자열이면 성공 하므로 무한 루프가 생성 됩니다. while true실제로는 항상 성공하는 이름의 명령을 실행 합니다 true.
chepner

4
안에 변수를 넣지 마십시오 $(). 당신은 넣어 명령 내부 $().
와일드 카드

답변:


23

인용 부호는 "단어 분할"을 방지합니다. 즉, 공백 문자 (또는 기본 $IFS쉘 변수 의 값에 정의 된대로 공백, 탭 및 줄 바꿈)에서 변수를 여러 항목으로 분류합니다 .

예를 들어

$ var="one two"
$ howmany(){ echo $#;  }
$ howmany $var
2
$ howmany "$var"
1

여기에 howmany얼마나 많은 위치 매개 변수가 제공되는지 알려주 는 함수를 정의합니다 . 보시다시피, 변수에 전달되는 두 개의 항목이 있으며 따옴표로 변수의 텍스트가 하나의 단위로 처리됩니다.

정보를 정확하게 전달하는 데 중요합니다. 예를 들어, 변수에 파일 경로가 있고 파일 이름에 경로 어딘가에 공백이 있으면 실행하려는 명령이 실패하거나 부정확 한 결과를 제공 할 수 있습니다. $var변수 를 사용하여 파일을 만들려고하면 touch $var두 개의 파일이 있지만 touch "$var"하나만 생성됩니다.

당신도 마찬가지입니다 [ "$currentoutput" != "$lastoutput" ]. 이 특정 테스트는 두 문자열을 비교합니다. 테스트가 실행될 때 [명령은 3 개의 인수 (텍스트 문자열, !=연산자 및 다른 텍스트 문자열)를 확인해야합니다. 큰 따옴표를 유지하면 단어가 분리되는 것을 막을 수 있으며 [명령은이 세 가지 인수를 정확하게 봅니다. 변수를 따옴표로 묶지 않으면 어떻게됩니까?

$ var="hello world"
$ foo="hi world"
$ [ $var != $foo ]
bash: [: too many arguments
$ 

여기서 단어 분리가 발생하고 대신 [두 개의 문자열 helloworld그 뒤에 !=, 두 개의 다른 문자열이 표시됩니다 hi world. 핵심은 큰 따옴표없이 변수의 내용은 하나의 전체 항목이 아닌 별도의 단위로 이해된다는 것입니다.

명령 대체를 할당 할 때와 같이 큰 따옴표가 필요하지 않습니다.

var=$( df )

당신은이 곳에 df명령의 출력이 저장 var. 그러나 $(...)실제로 출력을 별도의 항목으로 처리하지 않으려는 경우 변수를 큰 따옴표로 묶고 명령 대체를 사용하는 것이 좋습니다.


부수적으로

while [ true ]

일부가 될 수 있습니다

while true

[인수를 평가하는 명령 [ whatever ]이며 내부 내용에 관계없이 항상 참입니다. 대조적으로, 항상 성공 종료 상태를 반환 while true하는 명령 true을 사용하십시오 (그리고 정확히 while루프가 필요합니다). 차이점은 조금 더 명확하고 테스트가 덜 수행된다는 것입니다. 또는 :대신에 사용할 수도 있습니다true

큰 따옴표는 echo "" date and Time부분적으로 제거 될 수 있습니다. 그들은 단지 빈 문자열을 삽입하고 출력에 여분의 공간을 추가합니다. 원하는 경우 자유롭게 보관하십시오. 그러나이 경우 특별한 기능적 가치는 없습니다.

lsusb >> test.log

이 부분은 아마도로 대체 될 수 있습니다 echo "$currentoutput" >> test.log. lsusb에서 이미 실행 한 후 다시 실행할 이유가 없습니다 currentoutput=$(lsusb). 출력 에서 후행 줄 바꿈 을 유지 해야하는 경우 -명령을 여러 번 실행하는 값을 볼 수 있지만 lsusb필요하지 않은 경우 . 내장 명령이 아닌 명령을 호출 할 때마다 CPU, 메모리 사용 및 실행 시간 (명령이 메모리에서 사전로드되어 있음)이 발생하기 때문에 호출하는 외부 명령이 적을수록 좋습니다.


또한보십시오:


1
좋은 대답은, 아직하지 않았다면에 관한 책을 써야합니다 bash. 그러나 마지막 부분에는 echo "$currentoutput" >> test.log 더 좋지 않아야 printf '%s\n' "$currentoutput" >> test.log 합니까?
pLumo April

2
@RoVo 예, printf이식성을 선호합니다. 여기서 bash 특정 스크립트를 사용하고 있기 때문에을 사용하도록 변명 할 수 있습니다 echo. 그러나 당신의 관찰은 매우 정확합니다
Sergiy Kolodyazhnyy

1
@SergiyKolodyazhnyy, ... echo쉘이 bash 로 알려져 있고 xpg_echoand 및 posix플래그 의 값이 알려진 경우에도 완전히 신뢰할 수 있는지 확실하지 않습니다 . 값이 -n또는 -e일 수 있으면 인쇄하는 대신 사라질 수 있습니다.
Charles Duffy

4

에서 currentoutput="$(lsusb)"lsusb 변수 아니다, 그것은 명령입니다. 이 문장의 기능은 lsusb명령 을 실행 하고 출력을 currentoutput변수에 할당 합니다.

이전 구문은

currentoutput=`lsusb`

많은 예제와 스크립트에서 찾을 수 있습니다

질문의 다른 부분에 대답하려면 bash에서 if [ ]구문 if이 어떻게 정의 되는지 입니다. https://www.tldp.org/LDP/Bash-Beginners-Guide/html/sect_07_01.html 에서 자세히 알아보십시오.


3
그것이 [ ]실제로 test명령 이라고 말하는 것이 중요하다고 생각합니다 . if종료 코드의 0 또는 0이 아닌 테스트를 사용 하므로 다른 명령과 함께 명령문을 사용할 수도 있습니다 .
Arronical

... 실제로 실행하는 if grep -qe "somestring" file것보다 실행하는 것이 훨씬 낫기 grep -qe "somestring" file; if [ $? = 0 ]; then ...때문에 구문 if [ ...정의의 일부인 주장 은 if오해의 소지가 아니라 잘못된 관행으로 이어집니다.
Charles Duffy

4

다음은 외부 명령을 실행 command하고 출력을 반환합니다.

"$(command)"

괄호 / 괄호가 없으면 명령을 실행하는 대신 변수를 찾습니다.

"$variable"

차이점에 관해서 $variable하고 "$variable",이 때 중요한하게 $variable공간을 포함한다. 를 사용 "$variable"하면 내용에 공백이 포함되어 있어도 전체 변수 내용이 단일 문자열에 삽입됩니다. $variable변수의 내용을 사용할 때 여러 인수의 인수 목록으로 확장 될 수 있습니다.


안녕 @ thomasrutter, 미안 해요, 나는 따옴표를 의미 ... 나는 지금 내 의견을 편집!
Shankhara

1

반대로 bash는 [[ ... ]]over [ ... ]구문을 사용하여 테스트에서 변수를 인용하지 않고 다른 단어가 지적한 단어 분리 관련 문제를 피할 것을 권장합니다 .

[POSIX에서 실행되는 스크립트 #!/bin/sh또는 bash로 포팅되는 스크립트와의 POSIX 호환성을 위해 bash로 제공됩니다 . 대부분의 경우이를 위해 피해야합니다 [[.

예 :

# With [ - quotes are needed

$ foo='one two'; bar='one two'; [ $foo = $bar ] && echo "they're equal"
-bash: [: too many arguments

$ foo='one two'; bar='one two'; [ "$foo" = "$bar" ] && echo "they're equal"                                                                                                              
they're equal

# versus [[ - quotes not needed

$ foo='one two'; bar='one two'; [[ $foo = $bar ]] && echo "they're equal"
they're equal


bash그러한 권고를하지 않습니다. 그것은 제공하는 [[ ... ]] 더 편리 할 수있는 몇 가지 기능이 [ ... ]되지 않습니다,하지만 사용에 문제가없는 [ ... ] 정확하게는 .
chepner

@ chepner-어쩌면 내가 더 명확해야합니다. 분명히 그것은 bash 맨 페이지의 명시 적 권장 사항은 아니지만 주어진 [[모든 일을 [하고 계속 많은 [사람들이 여행을 한 다음 [[다시 [실패하고 버그를 흩어지게하기 위해 다시 기능을 개조하려고 시도 합니다. 지역 사회의 권고 까지 대부분의 관련 bash는 스타일 가이드는 조언을하지 않습니다로 사용하지 마십시오[ .
shalomb
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.