따옴표 없이 echo를 실행하는 것이 위험합니까?

따옴표 없이 echo를 실행하는 것이 위험합니까?

몇 가지 비슷한 주제를 본 적이 있지만 변수를 인용하지 않는다는 내용이 있는데, 이는 원치 않는 결과를 초래할 수 있다는 것을 알고 있습니다.

이 코드를 보고 다음 코드 줄이 실행될 때 실행할 무언가를 삽입할 수 있는지 궁금합니다.

echo run after_bundle

답변1

위에 추가 메모를 추가하세요.@Kusalananda의 훌륭한 답변.

echo run after_bundle

문제 없습니다. 이 세 매개변수의 어떤 문자도 echo쉘 특정 문자를 포함하도록 전달되지 않기 때문입니다.

그리고 (여기서 추가로 언급하고 싶은 점은) 이러한 바이트를 쉘 특정 문자로 변환할 수 있는 시스템 로케일이 없습니다.

이 문자들은 모두 무엇입니까?POSIX 호출휴대용 문자 세트. 이러한 문자는 POSIX 시스템의 모든 문자 집합에서 동일한 방식으로 나타나고 인코딩되어야 합니다.

따라서 명령줄은 로케일에 관계없이 동일하게 해석됩니다.

이제 이 이식 가능한 문자 집합 외부의 문자를 사용하기 시작하면 해당 문자가 셸에 특별하지 않더라도 해당 문자를 인용하는 것이 좋습니다. 왜냐하면 다른 로케일에서는 해당 문자를 구성하는 바이트가 다른 문자로 해석될 수 있기 때문입니다. 쉘 스페셜이 됩니다. 명령을 사용하든 echo다른 명령을 사용하든 문제는 echo셸이 코드를 구문 분석하는 방식이 아닙니다.

예를 들어 UTF-8에서는 다음과 같습니다.

echo voilà | iconv -f UTF-8 -t //TRANSLIT

인코딩은 à0xc3 0xa0입니다. 이제 쉘 스크립트에 해당 코드 줄이 있고 문자 세트가 UTF-8이 아닌 로케일을 사용하는 사용자가 쉘 스크립트를 호출하는 경우 이 두 바이트는 매우 다른 문자를 생성할 수 있습니다.

예를 들어, fr_FR.ISO8859-15로케일에서 일반적인 프랑스어 로케일은 프랑스어를 포함하는 표준 단일 바이트 문자 세트(영어를 포함한 대부분의 서유럽 언어와 동일)를 사용하며 0xc3 바이트는 문자로 해석되고 Ã0xa0은 문자로 해석됩니다. 비문자 집합 . 공백 문자를 끊습니다.

NetBSD³와 같은 일부 시스템에서는 잘림 방지 공백이 다음과 같이 처리됩니다.공백문자( isblank()true를 반환하고 일치함 )이므로 [[:blank:]]쉘과 마찬가지로 bash구문에서 토큰 구분 기호로 처리됩니다 .

echo이는 as 인수로 실행 하는 대신 $'voil\xc3\xa0'as 인수로 실행 중이므로 올바르게 인쇄 $'voil\xc3'되지 않음을 의미합니다 voilà.

BIG5, BIG5-HKSCS, GB18030, GBK와 같은 중국어 문자 세트의 경우 상황은 더욱 악화됩니다. 이 문자 세트에는 인코딩에 |, `, \(최악의 예를 들자면) 문자가 포함된 문자가 많이 있습니다. ¥은 아니지만 0x5c로 인코딩되어 있기 때문에 대부분의 도구에서는 \여전히 그렇게 처리됩니다 .\

예를 들어, 중국어 로케일을 사용하는 경우 zh_CN.gb18030다음과 같은 스크립트를 작성할 수 있습니다.

echo 詜 reboot

스크립트는 詜 rebootGB18030 또는 GBK를 사용하는 로케일, 唰 rebootBIG5 또는 BIG5-HKSCS를 사용하는 로케일, ASCII를 사용하는 C 로케일 또는 ISO8859-15 또는 UTF-8을 사용하는 로케일로 reboot출력 됩니다. GB18030 인코딩은 0xd4 0x7c이고 0x7c는 ASCII 인코딩이므로 다음을 |실행하게 됩니다.

 echo �| reboot

(그러나 �는 로케일에서 렌더링된 0xd4 바이트를 나타냅니다.) 덜 해로운 uname대안을 사용하는 예 reboot:

$ echo $'echo \u8a5c uname' | iconv -t gb18030 > myscript
$ LC_ALL=zh_CN.gb18030 bash ./myscript | sed -n l
\324| uname$
$ LC_ALL=C bash ./myscript | sed -n l
Linux$

( uname이미 실행 중).

따라서 내 제안은 이식 가능한 문자 집합 외부의 문자가 포함된 모든 문자열을 인용하는 것입니다.

\그러나 and의 인코딩은 이러한 문자 중 일부의 인코딩에서 발견되므로 or ( and /or는 여전히 특별함) 을 사용하지 않고 이식 가능한 문자 집합 외부의 문자를 참조하는 `것이 좋습니다 .\"..."$'...'`\'...'

'나는 로케일의 문자 세트 에 인코딩이 포함된 문자(물론 자체 제외)가 있는 시스템을 알지 못하므로 '이것이 '...'가장 안전할 것입니다.

일부 쉘은 $'\uXXXX'유니코드 코드 포인트를 기반으로 한 문자 표현도 지원합니다. zshWindows 및 Windows와 같은 셸 에서는 bash문자가 로케일의 문자 집합 인코딩에 삽입됩니다. 그러나 문자 집합에 해당 문자가 없으면 예기치 않은 동작이 발생할 수 있습니다. 이를 통해 쉘 코드에 ASCII가 아닌 문자를 삽입하는 것을 방지할 수 있습니다.

따라서 위의 내용은 다음과 같습니다.

echo 'voilà' | iconv -f UTF-8 -t //TRANSLIT
echo '詜 reboot'

또는:

echo $'voil\u00e0'
echo $'\u8a5c reboot'

(이러한 문자가 없는 로케일에서 실행하면 스크립트가 중단될 수 있습니다.)

아니면 더 나은 이유는 \( echo또는 적어도일부 echo구현, 최소한 Unix 호환 구현):

printf '%s\n' 'voilà' | iconv -f UTF-8 -t //TRANSLIT
printf '%s\n' '詜 reboot'

( \첫 번째 인수도 특별하므로 printf인코딩이 포함될 수 있는 경우 ASCII가 아닌 문자를 피하는 것이 가장 좋습니다 \.)

다음 작업도 수행할 수 있습니다.

'echo' 'voilà' | 'iconv' '-f' 'UTF-8' '-t' '//TRANSLIT'

(이것은 약간 과잉이지만 휴대용 문자 세트에 어떤 문자가 있는지 확실하지 않은 경우 마음을 편하게 할 수 있습니다)

또한 고대 `...`형태의 명령 대체(다른 수준의 백슬래시 처리를 도입함)를 절대 사용하지 말고 $(...)대신 이를 사용하십시오.


1은 기술적으로 유틸리티 echo에 인수로 전달되며 (호출 방법을 알려줌) , 3은 오늘날 대부분의 쉘에 내장되어 있으므로 3개의 인수 목록이 있는 파일의 에뮬레이션은 쉘에서 수행됩니다. 인수 목록은 명령이 주로 작동하는 인수이기 때문에 두 번째 인수( to )로 시작하는 것으로 생각하는 것이 일반적입니다.echoargv[0]argcechoexec()/bin/echoargv[1]argv[argc - 1]

² 주목할만한 예외 중 하나는 문자 세트에 Nor 문자 ja_JP.SJIS가 없는 FreeBSD 시스템의 터무니없는 로케일 입니다 !\~

³ 많은 시스템(FreeBSD, Solaris, GNU 시스템 제외)이 U+00A0을 [[:blank:]]UTF-8 로케일로 처리하는 반면, 다른 로케일(예: ISO8859-15를 사용하는 시스템)에서는 그렇게 하는 시스템이 거의 없습니다. 그런 문제.

답변2

특정 상황을 타겟팅

echo run after_bundle

인용은 필요하지 않습니다. 매개변수 echo는 정적 문자열이고 변수 확장이나 명령 대체 등을 포함하지 않으므로 따옴표가 필요하지 않습니다. 그것은 "단지 두 단어"입니다.스티븐은 지적했다., 그들은 추가로 구성됩니다휴대용 문자 세트).

"위험"은 쉘이 확장하거나 해석할 수 있는 변수 데이터를 처리할 때 발생합니다. 이 경우 셸이 올바른 작업을 수행하고 결과가 예상대로 나오도록 주의해야 합니다.

다음 두 질문에는 관련 정보가 포함되어 있습니다.


echo때때로 이 사이트의 답변에서 잠재적으로 유해한 명령을 "보호"하는 데 사용됩니다. 예를 들어 다음을 사용하여 파일을 삭제하거나 파일을 새 대상으로 이동하는 방법을 보여줄 수 있습니다.

echo rm "${name##*/}.txt"

또는

echo mv "$name" "/new_dir/$newname"

실제로 파일을 삭제하거나 이름을 바꾸는 대신 터미널에 명령이 출력됩니다. 그런 다음 사용자는 명령을 확인하고 괜찮아 보이는지 확인한 후 삭제 echo하고 다시 실행할 수 있습니다.

명령은 echo run after_bundle사용자에게 지시하는 것일 수도 있고, 결과를 알지 못한 채 실행하기에는 너무 위험한 "주석 처리된" 코드일 수도 있습니다.

이러한 방식으로 사용될 때 echo수정된 명령이 무엇을 하는지 알아야 하며 수정된 명령이 실제로 수행되는지 확인해야 합니다.안전하다(이럴 수도 있다아니요리디렉션이 포함되어 있고 파이프에서 사용하면 작동하지 않습니다.)

관련 정보