Bash의 명령에서 작은 따옴표 안의 변수 확장


393

작은 따옴표와 작은 따옴표 안에있는 다른 명령과 변수가 있는 bash 스크립트 에서 명령을 실행하고 싶습니다 .

예 : repo forall -c '....$variable'

이 형식에서는 $이스케이프되고 변수가 확장되지 않습니다.

다음 변형을 시도했지만 거부되었습니다.

repo forall -c '...."$variable" '

repo forall -c " '....$variable' "

" repo forall -c '....$variable' "

repo forall -c "'" ....$variable "'"

변수 대신 값을 대체하면 명령이 정상적으로 실행됩니다.

내가 어디로 잘못 가고 있는지 알려주세요.


33
repo forall -c ' ...before... '"$variable"' ...after...'
n. '대명사'm.

2
@nm 작은 따옴표는 repo 명령의 일부입니다. 나는 이것이 효과가 있다고 생각하지 않는다
Rachit

1
bash작은 따옴표를 먹는다. 에 있지 bash않거나 작은 따옴표는 repo명령 의 일부가 아닙니다 .
n. '대명사'm.

확실하지는 않지만 작은 따옴표가 필요한 경우 -c " '... refore ..."$ variable "... after ...'"작업을 할 수 없습니까?
ecv dec

bash 쉘 및 repo forall 명령에서 실행되는 bash 스크립트는 작은 따옴표 안에 매개 변수를 사용합니다. 실제 값을 대체하면 명령이 제대로 실행됩니다.
Rachit

답변:


621

작은 따옴표 안에는 예외없이 모든 것이 그대로 유지됩니다.

즉, 따옴표를 닫고 무언가를 삽입 한 다음 다시 입력해야합니다.

'before'"$variable"'after'
'before'"'"'after'
'before'\''after'

단어 연결은 단순히 병렬로 수행됩니다. 확인할 수 있듯이 위의 각 줄은 셸에 대한 단일 단어입니다. 따옴표 (상황에 따라 단일 또는 큰 따옴표)는 단어를 분리하지 않습니다. 그들은 단지 공백과 같은 다양한 특수 문자를 사용하지 않도록 해석에 사용된다 $, ;... 인용에 좋은 자습서는 마크 리드의 답변을 참조하십시오. 또한 관련 : bash에서 어떤 문자를 이스케이프해야합니까?

쉘이 해석 한 문자열을 연결하지 마십시오

변수를 연결하여 쉘 명령을 작성하지 마십시오. 이것은 SQL 조각 연결 (SQL injection!)과 유사한 나쁜 생각입니다.

일반적으로 명령에 자리 표시자를두고 호출자가 호출 인수 목록에서이를 수신 할 수 있도록 변수와 함께 명령을 제공 할 수 있습니다.

예를 들어, 다음은 매우 안전하지 않습니다. 이러지마

script="echo \"Argument 1 is: $myvar\""
/bin/sh -c "$script"

내용을 $myvar신뢰할 수없는 경우 다음과 같은 익스플로잇이 있습니다.

myvar='foo"; echo "you were hacked'

위의 호출 대신 위치 인수를 사용하십시오. 다음과 같은 호출이 더 좋습니다. 이용할 수 없습니다.

script='echo "arg 1 is: $1"'
/bin/sh -c "$script" -- "$myvar"

에 할당 할 때 단일 진드기를 사용 script한다는 점에 유의하십시오. 즉, 변수 확장이나 다른 형태의 해석없이 문자 그대로 사용됩니다.


작동하지 않는 @ Jo.SO. repo 명령은 첫 번째 따옴표가 닫힐 때까지 매개 변수 만 사용하기 때문입니다. 그 후에는 repo에 대해 무시되고 다른 오류가 발생합니다.
Rachit December

8
@Rachit-쉘이 그렇게 작동하지 않습니다. "some"thing' like'this껍질에 하나의 단어입니다. 인용 부호는 구문 분석과 관련하여 아무 것도 종료하지 않으며 셸이 호출 명령 이 인용 된 내용을 말할 수있는 방법이 없습니다.
Mark Reed

3
두 번째 문장 ( "작은 따옴표도 이스케이프 할 수 없습니다")은 작은 따옴표를 쉘의 블랙홀로 만듭니다.

@Evert : 더 잘 말하는 법을 모른다. 문장을 삭제했습니다.
Jo So

@JoSo 그것은 부끄러운 일입니다. 농담이 평평하지 않습니다.

96

repo명령은 어떤 종류의 따옴표를 가져도 상관 없습니다. 매개 변수 확장이 필요한 경우 큰 따옴표를 사용하십시오. 만약 당신이 많은 것을 백 슬래시해야하는 것을 의미한다면, 대부분의 경우 작은 따옴표를 사용한 다음, 그것들을 나누고 확장이 필요한 부분에 대해 두 배로 들어갑니다.

repo forall -c 'literal stuff goes here; '"stuff with $parameters here"' more literal stuff'

관심이 있다면 설명이 이어집니다.

쉘에서 명령을 실행할 때 해당 명령이 인수로받는 것은 null로 끝나는 문자열의 배열입니다. 이러한 문자열은 절대적으로 포함 할 수 있는 null 이외의 문자를.

그러나 쉘이 명령 행에서 문자열 배열을 작성할 때 일부 문자를 특수하게 해석합니다. 이것은 명령을보다 쉽게 ​​입력 할 수 있도록 설계되었습니다. 예를 들어, 공백은 일반적으로 배열에서 문자열 사이의 경계를 나타냅니다. 이런 이유로 개별 논쟁은 때때로 "단어"라고 불립니다. 그럼에도 불구하고 논쟁에는 공백이있을 수있다. 쉘에 원하는 것을 알려주는 방법이 필요합니다.

문자 (공백 또는 다른 백 슬래시 포함) 앞에 백 슬래시를 사용하여 해당 문자를 문자 그대로 처리하도록 쉘에 지시 할 수 있습니다. 그러나 다음과 같이 할 수 있습니다.

echo \"Thank\ you.\ \ That\'ll\ be\ \$4.96,\ please,\"\ said\ the\ cashier

... 불쾌 할 수 있습니다. 따라서 쉘은 대체 인용 부호를 제공합니다. 이들은 두 가지 주요 품종으로 제공됩니다.

큰 따옴표는 "그룹 따옴표"라고합니다. 와일드 카드와 별칭이 확장되는 것을 방지하지만 대부분 단어에 공백을 포함하기위한 것입니다. 매개 변수 및 명령 확장 (으로 표시되는 종류)과 같은 다른 것들이 $여전히 발생합니다. 물론 큰 따옴표 안에 리터럴 큰 따옴표를 원한다면 백 슬래시해야합니다.

echo "\"Thank you. That'll be \$4.96, please,\" said the cashier"

작은 따옴표는 좀 더 드라코 니안입니다. 그들 사이의 모든 것은 백 슬래시를 포함하여 문자 그대로 완전히 취해집니다. 작은 따옴표 안에 리터럴 작은 따옴표를 얻는 방법은 절대 없습니다.

다행스럽게도 쉘의 인용 부호는 단어 분리 문자가 아닙니다 . 그들 스스로는 단어를 끝내지 않습니다. 동일한 단어 내에서 다른 유형의 따옴표 사이를 포함하여 따옴표를 입력하거나 사용하여 원하는 결과를 얻을 수 있습니다.

echo '"Thank you. That'\''ll be $4.96, please," said the cashier'

따라서 한 쌍의 인용 부호, 백 슬래시 리터럴 단일 인용 부호, 열린 단일 인용 부호 시퀀스에 익숙해지는 데 시간이 많이 걸리지 만 훨씬 쉽습니다.

현대 쉘은 POSIX 표준에 의해 지정되지 않은 다른 인용 스타일을 추가했으며, 앞에 작은 따옴표 앞에 달러 기호가 붙습니다. 인용 된 문자열은 ANSI C 프로그래밍 언어의 문자열 리터럴과 유사한 규칙을 따르므로 "ANSI 문자열"및 $'... '"ANSI 인용"쌍 이라고도 합니다. 이러한 문자열 내에서 백 슬래시에 대한 위의 조언은 더 이상 적용되지 않습니다. 대신, 다시 특수화됩니다. 역 슬래시를 앞에 추가하여 리터럴 작은 따옴표 나 백 슬래시를 포함시킬 수있을뿐만 아니라 쉘은 ANSI C 문자 이스케이프를 확장합니다 ( \n줄 바꾸기, \t탭 및 \xHH문자 포함). 16 진 코드HH). 그렇지 않으면 작은 따옴표로 묶인 문자열로 작동합니다. 매개 변수 또는 명령 대체가 발생하지 않습니다.

echo $'"Thank you.  That\'ll be $4.96, please," said the cashier'

주목해야 할 것은 echo명령에 대한 인수로 수신 된 단일 문자열 이이 모든 예에서 정확히 동일 하다는 것 입니다. 쉘이 명령 행을 구문 분석 한 후에는 명령이 실행 된 방법을 알 수있는 방법이 없습니다. 원하는 경우에도 마찬가지입니다.


2
예. 지금은 이해. 완벽하게 작동합니다. 도와 주셔서 정말로 고맙습니다!
Rachit

6
이 답장은 굉장했습니다.
Vinícius Ferrão

1
는 IS $'string'형식 POSIX의 준수는? 또한 이름이 있습니까?
와일드 카드

2
@Wildcard $'string'는 POSIX 이외의 확장으로, "ANSI 문자열"이라고합니다. 나는 그 사실들을 답에 포함시켰다. 이러한 문자열은 대부분의 최신 Bourne 호환 쉘 (bash, dash, ksh (AT & T 및 PD) 및 zsh)에서 모두 지원합니다.
마크 리드


3

아래는 나를 위해 일한 것입니다-

QUOTE="'"
hive -e "alter table TBL_NAME set location $QUOTE$TBL_HDFS_DIR_PATH$QUOTE"

2
나는 TBL_HDFS_DIR_PATH가 사용자가 입력 한 btw를 제공하지 않기를 바란다. 이것은 멋진 SQL 인젝션을 허용 할 것이다.
domenukk

1
QUOTE별도의 변수를 넣는 것은 완전히 불필요한 것입니다. 큰 따옴표 안의 작은 따옴표는 단지 ​​일반 문자입니다. (또한 개인 변수에 대문자를 사용하지 마십시오.)
tripleee March

2

편집 : (문제의 의견에 따라 :)

나는 그때부터 이것을 조사해 왔습니다. 나는 레포가 누워있을 정도로 운이 좋았다. 여전히 명령을 작은 따옴표로 묶어야하는지 여부는 분명하지 않습니다. 나는 repo 구문을 조사했지만 당신이 필요하다고 생각하지 않습니다. 명령에 큰 따옴표를 사용한 다음 큰 따옴표를 이탈하면 필요한 작은 따옴표와 큰 따옴표를 사용할 수 있습니다.


도와 주셔서 감사합니다.
Rachit

2

그냥 printf를 사용하십시오

대신에

repo forall -c '....$variable'

printf를 사용하여 변수 토큰을 확장 변수로 바꿉니다.

예를 들면 다음과 같습니다.

template='.... %s'

repo forall -c $(printf "${template}" "${variable}")

이 고장; printf실제로 여기에서 아무것도 사지 않으며 명령 대체를 인용하지 않으면 새로운 인용 문제가 발생합니다.
tripleee

0

변수는 작은 따옴표를 포함 할 수 있습니다.

myvar=\'....$variable\'

repo forall -c $myvar

그들은 할 수 있지만 이것이 올바른 방법은 아닙니다. 여전히 "$myvar"큰 따옴표를 넣어야합니다.
tripleee

-2

이것이 당신을 위해 작동합니까?

eval repo forall -c '....$variable'

8
당신을 위해합니까? 이 질문은 5 살이고 이미 몇 가지 답변을
받았으며
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.