명령줄 매개변수에서 어떤 문자를 이스케이프해야 합니까?

명령줄 매개변수에서 어떤 문자를 이스케이프해야 합니까?

Bash에서 명령에 명령줄 인수를 지정할 때 어떤 문자를 이스케이프해야 합니까?

|Bash의 메타 문자인 공백, 탭 , , , , , , 및 으로 제한됩니까 ?&;()<>

답변1

일부 상황에서 다음 문자는 셸 자체에 특별한 의미를 가지며 매개변수에서 이스케이프해야 할 수도 있습니다.

특징 유니코드 이름 용법
` U+0060(악센트) 백틱 명령 대체
~ U+007E 틸데 물결표 확장
! U+0021 느낌표 역사적 확장
# U+0023 숫자 기호 해시 값 논평
$ U+0024 달러 표시 매개변수 확장
& U+0026 앰퍼샌드 백그라운드 명령
* U+002A 별표 파일 이름 확장자 및 와일드카드
( U+0028 왼쪽 괄호 서브쉘
) U+0029 오른쪽 대괄호 서브쉘
U+0009 라벨( ) 분사(공백)
{ U+007B 왼쪽 중괄호 왼쪽 버팀대 지원 확장
[ U+005B 왼쪽 대괄호 파일 이름 확장자 및 와일드카드
| U+007C 수직선 수직 스트립 관로
\ U+005C 역고상선 백슬래시 이스케이프 문자
; U+003B 세미콜론 별도의 명령
' U+0027 아포스트로피 아포스트로피 문자열 참조
" U+0022 따옴표 큰따옴표 보간이 포함된 문자열 참조
U+000A 줄 바꿈 새로운 팀 선을 넘어
< U+003C 미만 입력 리디렉션
> U+003E 보다 낫다 출력 리디렉션
? U+003F 물음표 파일 이름 확장자 및 와일드카드
U+0020 공간 분사1 (공백)

이 캐릭터 중 일부는 제가 링크한 캐릭터보다 더 많은 일과 더 많은 장소에서 사용됩니다.


이것이 명시적으로 선택 사항인 몇 가지 극단적인 경우가 있습니다.


개행 문자 이스케이프인용이 필요합니다— 백슬래시는 효과가 없습니다. 에 나열된 다른 문자IFS유사한 처리가 필요합니다. 탈출 ]하거나 을 할 필요 }는 없지만하다)연산자이므로 이스케이프해야 합니다 .

이러한 문자 중 일부는 실제로 탈출해야 할 때 다른 문자보다 더 엄격한 제한을 적용합니다. 예를 들어, a#b괜찮지만 a #b주석이므로 >두 경우 모두 이스케이프가 필요합니다. 그럼에도 불구하고 보수적으로 피하는 것이 나쁠 것은 없으며 미묘한 차이점을 기억하는 것보다 쉽습니다.

명령 이름 자체가 셸 키워드( if, for, do)인 경우 해당 키워드도 이스케이프하거나 인용해야 합니다. 유일하게 흥미로운 점은 in항상 키워드이기 때문에 명확하지 않다는 것입니다. 너아니요(어리석게도!) 이러한 키워드 중 하나의 이름을 따서 명령 이름을 지정한 경우 인수에 사용된 키워드에 대해서만 이 작업을 수행하면 됩니다. 쉘 연산자( (&)는 사용될 때마다 항상 인용이 필요합니다.


1 스테판은 다른 점을 지적합니다.단일 바이트해당 지역의 공백 문자탈출도 필요합니다. 가장 일반적이고 합리적인 로케일(적어도 C 또는 UTF-8 기반의 로케일)에서는 위의 공백 문자일 뿐입니다. U+00A0 줄바꿈 없는 공백은 Solaris, BSD 및 OS X를 포함한 일부 ISO-8859-1 로케일에서 공백으로 처리됩니다(제 생각에는 잘못된 것 같습니다). 알 수 없는 로케일을 다루는 경우 문자를 포함한 모든 것이 포함될 수 있으므로 행운을 빕니다.

공백으로 간주되는 단일 바이트가 있을 수 있다고 생각할 수 있습니다.이내에공백이 아닌 멀티바이트 문자이므로 전체 문자를 따옴표로 묶는 것 외에는 이스케이프할 수 있는 방법이 없습니다. 이는 이론적인 문제가 아닙니다. 위의 ISO-8859-1 로케일에는 A0공백으로 처리되는 바이트가 있을 수 있습니다.이내에UTF-8로 인코딩된 "à"( )와 같은 멀티바이트 문자입니다 C3 A0. 이러한 문자를 안전하게 처리하려면 해당 문자를 인용해야 합니다 "à". 이 동작은 스크립트를 작성하는 환경의 로케일 구성이 아니라 스크립트가 실행되는 환경의 로케일 구성에 따라 달라집니다.

나는 이 행동이 여러 가지 방법으로 깨질 수 있다고 생각하지만, 우리는 주어진 카드를 가지고 놀아야 합니다. 자체 동기화되지 않는 멀티바이트 문자 집합을 사용하는 경우 가장 안전한 방법은 모든 항목을 인용하는 것입니다. UTF-8이나 C를 사용하면 (현재로서는) 안전합니다.

답변2

GNU Parallel에서는 이것이 테스트되었고 널리 사용되었습니다:

$a =~ s/[\002-\011\013-\032\\\#\?\`\(\)\{\}\[\]\^\*\<\=\>\~\|\; \"\!\$\&\'\202-\377]/\\$&/go;
# quote newline as '\n'                                                                                                         
$a =~ s/[\n]/'\n'/go;

bash, dash, ash, ksh, 및 에서 zsh테스트 되었습니다 fish. 일부 문자는 일부 (버전) 쉘에서 인용할 필요가 없지만 위의 내용은 테스트된 모든 쉘에서 작동합니다.

문자열을 참조하려는 경우 다음으로 파이프할 수 있습니다 parallel --shellquote.

printf "&*\t*!" | parallel --shellquote

답변3

Perl의 경량 이스케이프 솔루션의 경우 작은따옴표 원칙을 따릅니다. 작은따옴표 안의 Bash 문자열에는 작은따옴표 자체를 제외한 모든 문자가 포함될 수 있습니다.

내 코드:

my $bash_reserved_characters_re = qr([ !"#$&'()*;<>?\[\\`{|~\t\n]);

while(<>) {
    if (/$bash_reserved_characters_re/) {
        my $quoted = s/'/'"'"'/gr;
        print "'$quoted'";
    } else {
        print $_;
    }
}

예제 실행 1:

$ echo -n "abc" | perl escape_bash_special_chars.pl
abc

예제 실행 2:

echo "abc" | perl escape_bash_special_chars.pl
'abc
'

예제 실행 3:

echo -n 'ab^c' | perl escape_bash_special_chars.pl
ab^c

예제 실행 4:

echo -n 'ab~c' | perl escape_bash_special_chars.pl
'ab~c'

예제 실행 5:

echo -n "ab'c" | perl escape_bash_special_chars.pl
'ab'"'"'c'

echo 'ab'"'"'c'
ab'c

관련 정보