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


11

비슷한 주제 몇 가지를 보았지만 변수를 인용하지 않는 것을 말하고 있습니다. 이는 원치 않는 결과를 초래할 수 있습니다.

나는이 코드를 보았고이 코드 줄이 실행될 때 실행될 것을 주입 할 수 있는지 궁금해했다.

echo run after_bundle


다음과 같은 경우에이 문제가 발생했습니다. target = "*** LIVE SERVER ***"; 에코 대상 : $ target; ***는 폴더 목록으로 확장되었습니다 ... 😬
Matt Parkins

답변:


17

특정한 경우

echo run after_bundle

인용은 필요하지 않습니다. echo변수 확장이나 명령 대체 등을 포함하지 않는 정적 문자열 이기 때문에 따옴표가 필요 하지 않습니다. "두 단어 만"( Stéphane이 지적한 대로 추가로 휴대용 문자 세트구성됨 )입니다.

"위험"은 쉘이 확장되거나 해석 될 수있는 변수 데이터를 처리 할 때 발생합니다. 이러한 경우, 쉘이 올바른 작업을 수행하고 결과가 의도 한 것임을주의해야합니다.

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


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

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

또는

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

실제로 파일을 제거하거나 이름을 바꾸는 대신 터미널에서 명령을 출력합니다. 그런 다음 사용자는 명령을 검사하고 명령이 정상인지 확인하고를 제거한 echo다음 다시 실행할 수 있습니다.

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

사용 echo과 같이, 하나는 수정 된 명령을 수행하고 수정 명령이 실제로 하나 반드시 보증을 알고있다 입니다 (잠재적 것이 안전 하지 가 리디렉션이 포함 된 경우, 그리고 파이프 라인에 그것을 사용하는 등 작업을하지 않습니다)


그러나 따옴표를 추가 하는 것만으로는 쉘이 무엇을하는지 알기 에는 충분 하지 않습니다. 그렇다고 해서 출력이 똑같다는 echo rm "first file.txt" "second file.txt"것과는 전혀 다릅니다 echo rm "first" "file.txt" "second" "file.txt". 쉘 명령을 출력 으로 생성하려면 전달 된 것으로 평가되는 구문 따옴표를 다시 생성하는 동등한 것을 사용해야 합니다 . printf '%q ' rm "first file.txt" "second file.txt"; echoargv
찰스 더피

@CharlesDuffy 정말 아무도 복사 붙여 넣기 디버깅 출력을 희망하고 그것을 셸에서 실행하지 않기를 바랍니다!
Kusalananda

1
쉘 명령을 생성 한 다음 파이핑 sh하는 것은 일반적이지 않은 패턴이 아니며 사람들이 " foo명령 줄에서 실행할 때 왜 작동 echo합니까?하지만 줄 앞의 정확한 문자열을 생성하는이 스크립트는 그렇지 않습니다. " 여기서 항상 발생 합니다 . 요컨대, 버그를 숨기면 디버깅 출력 이 도움이되지 않습니다. 버그가 인용과 관련이 있으면 echo공개하지 않습니다.
Charles Duffy 1

27

@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와 함께 $'voil\xc3\xa0'인수로, 그들은 그것을 실행 $'voil\xc3'이 인쇄되지 않습니다 의미 인수로 voilà올바르게.

그것은 인코딩과 같은 인코딩을 포함 많은 문자가 BIG5, BIG5-HKSCS, GB18030, GBK 같은 중국어 문자 세트와 많이 악화 |, `, \마이크로 소프트 한자 일명 제외하고 (또한 우스꽝스러운 SJIS (최악의 이름을 지정합니다) 그것은 ¥대신 0x5c로 인코딩되어 있기 때문에 대부분의 도구에 의해 \처리됩니다 \).

예를 들어, zh_CN.gb18030중국어 로켈 인 경우 다음과 같은 스크립트를 작성합니다.

echo  reboot

이 스크립트는 詜 rebootGB18030 또는 GBK를 사용하는 로케일, 唰 rebootBIG5 또는 BIG5-HKSCS를 사용하는 로케일로 출력 하지만 ASCII를 사용하는 C 로케일 또는 ISO8859-15 또는 UTF-8을 사용하는 로케일 reboot은 GB18030 인코딩으로 인해 실행됩니다. of 는 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달렸다).

따라서 휴대용 문자 집합 외부의 문자가 포함 된 모든 문자열을 인용하는 것이 좋습니다.

그러나 일부 문자 의 인코딩에서 \및 의 인코딩 `이 발견되므로 \또는 "..."또는 $'...'( `또는 \여전히 특수한 내부) 를 사용하지 '...'말고 휴대용 문자 세트 외부의 문자를 인용 하는 것이 좋습니다.

나는 (이외의 캐릭터는 어떤 캐릭터가있는 로케일 모든 시스템의 인식 아니에요 '인코딩의 인코딩을 포함 물론 자체) '사람들은, 그래서 '...'확실히 안전한해야합니다.

또한 여러 쉘은 $'\uXXXX'유니 코드 코드 포인트를 기반으로 문자를 표현 하는 표기법을 지원합니다 . zshand와 같은 쉘 bash에서 문자는 로케일의 문자 세트로 인코딩되어 삽입됩니다 (문자 세트에 해당 문자가없는 경우 예기치 않은 동작이 발생할 수 있음). 따라서 쉘 코드에 비 ASCII 문자를 삽입하지 않아도됩니다.

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

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

또는:

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

(주의 사항을 사용하면 해당 문자가없는 로케일에서 실행될 때 스크립트가 중단 될 수 있습니다).

또는 더 \특별하기 때문에 echo(또는 적어도 일부 echo 구현, 적어도 유닉스 호환 구현) :

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

( \의 첫 번째 인수에서도 특별 printf하므로의 인코딩을 포함 할 수있는 경우 비 ASCII 문자도 사용하지 않는 것이 좋습니다 \.)

다음을 수행 할 수도 있습니다.

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

(이는 과잉이지만 휴대용 문자 세트에 어떤 문자가 있는지 확실하지 않으면 안심할 수 있습니다)

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


¹ 기술적으로 유틸리티 echo에 대한 인수로도 전달됩니다 echo(호출 방법을 알려주기 위해). argv[0]그리고 argc오늘날에는 대부분의 쉘 echo에 내장되어 있지만 3 개의 인수 목록이 exec()있는 /bin/echo파일 의 파일은 다음과 같이 시뮬레이션됩니다. 껍질. 또한 명령 목록이 주로 수행되는 인수이므로 두 번째 인수 ( argv[1]~ argv[argc - 1])로 시작하는 인수 목록을 고려하는 것이 일반적 입니다.

² ja_JP.SJIS문자 세트 \~문자 도 없는 FreeBSD 시스템 의 음란 한 로케일 이라는 점에서 주목할만한 예외입니다 !

³ 많은 시스템 (GNU 시스템이 아닌 Solaris, FreeBSD)에서는 U + 00A0을 [[:blank:]]UTF-8 로켈 로 간주하지만 ISO8859-15를 사용하는 것과 같은 다른 로케일에서는 이러한 종류의 문제를 피할 수있는 시스템이 거의 없습니다.


당신의 첫 번째 단락에서, 당신이 "...에 전달하는 3 개 인수의 문자의 우리에게 echo, 나는 단지이 인수를 명령에 전달되고 계산 ..." echo나는이 믿을 수있는 인수 run하고 after_bundle, 관리하는 방법을 설명하는 세 어린가?
Ferrybig

1
@ViktorFonic, 인수 수에 대한 편집을 참조하십시오 (주된 문제는와 관련이 없음 echo). 유틸리티에 (exec -a foo /bin/echo --help)임의의 첫 번째 인수를 전달하는 방법은 GNU 시스템 및 GNU 셸을 참조하십시오 /bin/echo.
Stéphane Chazelas

@Ferrybig Stephane의 편집, 각주 1을 참조하십시오. 일반적인 C 스타일의 명령 인수는 인수 배열이며 argv [0]은 실행 파일 이름 자체입니다. $0쉘의 유사 하고 위치 매개 변수입니다.
Sergiy Kolodyazhnyy

로 변환 iconv된 373 개의 인코딩이 있습니다 . (예를 들어) 시도 :ESC'printf '\x1b'|iconv -f utf8 -t IBM-937|xxd
이삭

일부 코드 포인트 (ESC 이외의)가로 변환되는 173 인코딩이 있습니다 '. 시도하십시오 printf '\u2804' | iconv -f utf8 -t BRF | xxd. 코드 포인트가 많은 인코딩이 '있습니다. UCS-4의 약 8695 개의 코드 포인트가 '됩니다. 시도하십시오 printf '\U627' | iconv -cf utf-8 -t UCS-4. 여러 (37) 인코딩은 문자 0x127을로 변환합니다 '. Tryprintf '\U127' | iconv -cf utf8 -t UCS2 |xxd
Isaac
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.