[bash] Bash를 사용할 때 어떤 문자를 이스케이프해야합니까?

Bash에서 이스케이프해야하는 포괄적 인 문자 목록이 있습니까? 그냥 확인할 수 있습니까 sed?

특히 %탈출 해야하는지 여부를 확인하고있었습니다 . 나는 시도했다

echo "h%h" | sed 's/%/i/g'

탈출하지 않고 잘 작동했습니다 %. %탈출 할 필요가 없다는 의미 입니까? 이것이 필요성을 점검하는 좋은 방법 이었습니까?

그리고 더 일반적인 : 그들은 탈출하기 위해 동일한 문자입니다 shellbash?



답변

쉽고 안전한 두 가지 규칙이 sh있습니다 bash.

1. 전체 문자열을 작은 따옴표로 묶습니다.

작은 따옴표 자체를 제외한 모든 문자에 적용됩니다. 작은 따옴표를 이스케이프하려면 따옴표를 닫고 작은 따옴표를 삽입 한 후 따옴표를 다시여십시오.

'I'\''m a s@fe $tring which ends in newline
'

sed 명령 : sed -e "s/'/'\\\\''/g; 1s/^/'/; \$s/\$/'/"

2. 백 슬래시로 모든 문자를 이스케이프

이것은 개행을 제외한 모든 문자에 적용됩니다. 줄 바꿈 문자의 경우 작은 따옴표 나 큰 따옴표를 사용하십시오. 빈 문자열은 여전히 ​​처리해야합니다.""

\I\'\m\ \a\ \s\@\f\e\ \$\t\r\i\n\g\ \w\h\i\c\h\ \e\n\d\s\ \i\n\ \n\e\w\l\i\n\e"
"

sed 명령 : sed -e 's/./\\&/g; 1{$s/^$/""/}; 1!s/^/"/; $!s/$/"/'.

2b. 더 읽기 쉬운 버전 2

와 같은 쉽고 안전한 문자 집합 [a-zA-Z0-9,._+:@%/-]이 있습니다.

I\'m\ a\ s@fe\ \$tring\ which\ ends\ in\ newline"
"

sed 명령 : LC_ALL=C sed -e 's/[^a-zA-Z0-9,._+@%/-]/\\&/g; 1{$s/^$/""/}; 1!s/^/"/; $!s/$/"/'.


sed 프로그램에서는 마지막 입력 행이 줄 바꿈 바이트로 끝나는 지 여부를 알 수 없습니다 (빈 경우 제외). 그래서 위의 sed 명령이 그렇지 않다고 가정합니다. 인용 된 줄 바꿈을 수동으로 추가 할 수 있습니다.

쉘 변수는 POSIX 의미의 텍스트에 대해서만 정의됩니다. 이진 데이터 처리가 정의되지 않았습니다. 중요한 구현의 경우 바이너리는 NUL 바이트를 제외하고 작동합니다 (변수는 C 문자열로 구현되고 C 문자열, 즉 프로그램 인수로 사용되기 때문). latin1과 같은 “이진”로캘로 전환해야합니다 .


(의 POSIX 사양을 읽으면 규칙을 쉽게 확인할 수 있습니다 sh. bash의 경우 @AustinPhillips에 의해 링크 된 참조 매뉴얼을 확인하십시오)


답변

쉘 입력으로 재사용 할 수있는 형식

특별 printf 형식 지시자 ( %q요청 이런 종류의 내장은) :

printf [-v var] 형식 [인수]

 %q     causes printf to output the corresponding argument
        in a format that can be reused as shell input.

일부 샘플 :

read foo
Hello world
printf "%q\n" "$foo"
Hello\ world

printf "%q\n" $'Hello world!\n'
$'Hello world!\n'

변수를 통해서도 사용할 수 있습니다 :

printf -v var "%q" "$foo
"
echo "$var"
$'Hello world\n'

모든 (128) ASCII 바이트로 빠른 검사 :

128에서 255까지의 모든 바이트를 이스케이프해야합니다.

for i in {0..127} ;do
    printf -v var \\%o $i
    printf -v var $var
    printf -v res "%q" "$var"
    esc=E
    [ "$var" = "$res" ] && esc=-
    printf "%02X %s %-7s\n" $i $esc "$res"
done |
    column

이것은 다음과 같이 렌더링해야합니다.

00 E ''         1A E $'\032'    34 - 4          4E - N          68 - h
01 E $'\001'    1B E $'\E'      35 - 5          4F - O          69 - i
02 E $'\002'    1C E $'\034'    36 - 6          50 - P          6A - j
03 E $'\003'    1D E $'\035'    37 - 7          51 - Q          6B - k
04 E $'\004'    1E E $'\036'    38 - 8          52 - R          6C - l
05 E $'\005'    1F E $'\037'    39 - 9          53 - S          6D - m
06 E $'\006'    20 E \          3A - :          54 - T          6E - n
07 E $'\a'      21 E \!         3B E \;         55 - U          6F - o
08 E $'\b'      22 E \"         3C E \<         56 - V          70 - p
09 E $'\t'      23 E \#         3D - =          57 - W          71 - q
0A E $'\n'      24 E \$         3E E \>         58 - X          72 - r
0B E $'\v'      25 - %          3F E \?         59 - Y          73 - s
0C E $'\f'      26 E \&         40 - @          5A - Z          74 - t
0D E $'\r'      27 E \'         41 - A          5B E \[         75 - u
0E E $'\016'    28 E \(         42 - B          5C E \\         76 - v
0F E $'\017'    29 E \)         43 - C          5D E \]         77 - w
10 E $'\020'    2A E \*         44 - D          5E E \^         78 - x
11 E $'\021'    2B - +          45 - E          5F - _          79 - y
12 E $'\022'    2C E \,         46 - F          60 E \`         7A - z
13 E $'\023'    2D - -          47 - G          61 - a          7B E \{
14 E $'\024'    2E - .          48 - H          62 - b          7C E \|
15 E $'\025'    2F - /          49 - I          63 - c          7D E \}
16 E $'\026'    30 - 0          4A - J          64 - d          7E E \~
17 E $'\027'    31 - 1          4B - K          65 - e          7F E $'\177'
18 E $'\030'    32 - 2          4C - L          66 - f
19 E $'\031'    33 - 3          4D - M          67 - g      

첫 번째 필드가 바이트의 16 진수 값인 E경우 두 번째는 문자를 이스케이프해야하는 경우 포함 하고 세 번째 필드는 이스케이프 된 문자 표시를 표시합니다.

,?

당신은하지 않는 일부 문자를 볼 수 항상 같은 이스케이프 할 필요를 ,, }하고 {.

그래서하지 항상 하지만 언젠가 :

echo test 1, 2, 3 and 4,5.
test 1, 2, 3 and 4,5.

또는

echo test { 1, 2, 3 }
test { 1, 2, 3 }

그러나주의 :

echo test{1,2,3}
test1 test2 test3

echo test\ {1,2,3}
test 1 test 2 test 3

echo test\ {\ 1,\ 2,\ 3\ }
test  1 test  2 test  3

echo test\ {\ 1\,\ 2,\ 3\ }
test  1, 2 test  3 


답변

bash 에서 다른 사람이 RTFM을 갖지 못하게하려면 :

큰 따옴표 문자를 묶는 것은 제외하고, 따옴표 내의 모든 문자의 리터럴 값을 보존 $, `, \,와, 역사 확장을 사용하는 경우, !.

… 따라서 그것들을 피하고 (물론 인용문 자체도) 괜찮을 것입니다.

좀 더 보수적 인 ‘의심 할 때 이스케이프’접근 방식을 사용하는 경우 식별자 문자 (예 : ASCII 문자, 숫자 또는 ‘_’)를 이스케이프 처리하지 않고 특별한 의미의 문자를 가져 오는 것을 피할 수 있습니다. 이것들은 (즉, 이상한 POSIX-ish 쉘에서) 특별한 의미를 가지지 않으므로 탈출해야 할 가능성은 거의 없습니다.


답변

print '%q' 기술을 사용하여 루프를 실행하여 어떤 문자가 특별한 지 알아낼 수 있습니다.

#!/bin/bash
special=$'`!@#$%^&*()-_+={}|[]\\;\':",.<>?/ '
for ((i=0; i < ${#special}; i++)); do
    char="${special:i:1}"
    printf -v q_char '%q' "$char"
    if [[ "$char" != "$q_char" ]]; then
        printf 'Yes - character %s needs to be escaped\n' "$char"
    else
        printf 'No - character %s does not need to be escaped\n' "$char"
    fi
done | sort

이 출력을 제공합니다.

No, character % does not need to be escaped
No, character + does not need to be escaped
No, character - does not need to be escaped
No, character . does not need to be escaped
No, character / does not need to be escaped
No, character : does not need to be escaped
No, character = does not need to be escaped
No, character @ does not need to be escaped
No, character _ does not need to be escaped
Yes, character   needs to be escaped
Yes, character ! needs to be escaped
Yes, character " needs to be escaped
Yes, character # needs to be escaped
Yes, character $ needs to be escaped
Yes, character & needs to be escaped
Yes, character ' needs to be escaped
Yes, character ( needs to be escaped
Yes, character ) needs to be escaped
Yes, character * needs to be escaped
Yes, character , needs to be escaped
Yes, character ; needs to be escaped
Yes, character < needs to be escaped
Yes, character > needs to be escaped
Yes, character ? needs to be escaped
Yes, character [ needs to be escaped
Yes, character \ needs to be escaped
Yes, character ] needs to be escaped
Yes, character ^ needs to be escaped
Yes, character ` needs to be escaped
Yes, character { needs to be escaped
Yes, character | needs to be escaped
Yes, character } needs to be escaped

,조금 의심스러운 것처럼 보이는 결과도 있습니다. @CharlesDuffy의 입력을 얻는 것이 흥미로울 것입니다.


답변

이스케이프가 필요한 문자는 Bourne 또는 POSIX 셸에서 Bash와 다릅니다. 일반적으로 (매우) Bash는 해당 쉘의 상위 세트이므로 shellBash에서 탈출해야합니다.

좋은 규칙은 “의심 스럽다면 탈출”입니다. 그러나 일부 문자를 이스케이프하면와 같은 특별한 의미가 \n있습니다. 이들은 man bash아래 페이지에 Quoting나와 있습니다.echo 있습니다.

그 외에는 영숫자가 아닌 문자를 피하십시오. 더 안전합니다. 나는 단 하나의 결정적인 목록을 모른다.

매뉴얼 페이지는 한 곳에는 없지만 어딘가에 나열되어 있습니다. 언어를 배우십시오, 그것이 확실한 방법입니다.

나를 사로 잡은 것은이다 !. 이것은 Bash (및 csh)의 특수 문자 (역사 확장)이지만 Korn 쉘에는 없습니다. 심지어 echo "Hello world!"문제가 있습니다. 평소와 같이 작은 따옴표를 사용하면 특별한 의미가 제거됩니다.


답변

bash 문자열에 대해 이야기하고 있다고 가정합니다. 이스케이프에 대한 요구 사항이 다른 여러 유형의 문자열이 있습니다. 예. 작은 따옴표 문자열은 큰 따옴표 문자열과 다릅니다.

가장 좋은 참조는 인용입니다 bash 매뉴얼 섹션입니다.

이스케이프해야하는 문자를 설명합니다. 히스토리 확장과 같이 사용 가능한 옵션에 따라 일부 문자를 이스케이프해야 할 수도 있습니다.


답변

자동 완성을 사용할 때 bash가 자동으로 일부 문자를 이스케이프하는 것으로 나타났습니다.

예를 들어,라는 디렉토리가 있으면 dir:Abash는 다음과 같이 자동 완성됩니다.dir\:A

이를 사용하여 ASCII 테이블의 문자를 사용하여 몇 가지 실험을 실행하고 다음 목록을 도출했습니다.

자동 완성시 bash가 이스케이프되는 문자 : (공백 포함)

 !"$&'()*,:;<=>?@[\]^`{|}

bash가 이스케이프하지 않는 문자 :

#%+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~

( /디렉토리 이름에 사용할 수 없으므로 제외 했습니다)