Bourne Shell에서 $가 포함된 이스케이프 문자열을 에코하는 방법은 무엇입니까?
user@server:~$ cat test.sh
#!/bin/sh
echo $1
user@server:~$ ./test.sh \$sad\$test
$sad$test
다음과 같이 이스케이프된 버전을 반환하고 싶습니다.
user@server:~$ ./test.sh \$sad\$test
\$sad\$test
나는 sed와 awk를 사용하여 몇 가지 트릭을 시도했지만 성공하지 못했습니다. 어떤 지침이라도 대단히 감사하겠습니다.
답변1
문자열이 "셸 인용"으로 표시되기를 원한다고 가정합니다.
이것인쇄 기능내장 명령은케시,세게 때리다, 그리고다루기 힘든모두 %q
형식 지정자를 이해합니다. 실제 출력은 정규화되지 않으며 입력 문자열에 따라 달라질 수 있습니다(아래 참조). 출력 형식의 변경으로 인해 한 셸의 출력을 다른 셸에서 사용하지 못할 수도 있습니다(특히 대상 셸이 기능이 덜 풍부한 셸인 경우).금연 건강 증진 협회,스프린트, 등. ).
다루기 힘든매개변수 확장에서 직접 인용문을 생성하는 기능도 지원됩니다.
echo "${(q)1}" # backslashes, with $'' for unprintable/invalid characters
echo "${(qq)1}" # single quotes
echo "${(qqq)1}" # double quotes
echo "${(qqqq)1}" # $'' quoting
"직접 수행"하고 싶다면 가장 쉽고 신뢰할 수 있는 방법은 자신만의 작은따옴표를 생성하는 것입니다. 간단한 알고리즘은 다음과 같습니다.
- 작은따옴표를 시퀀스로 변경합니다
'\''
. - 결과를 작은따옴표로 묶습니다.
작은 따옴표는 완전히 literal1 이기 때문에 Bourne과 같은 쉘에서 작동합니다 . 작은따옴표를 나타내려면 현재 작은따옴표 범위를 끝내고 백슬래시로 이스케이프된 작은따옴표를 제공하고 문자열의 나머지 부분에 작은따옴표를 다시 사용하세요. 위의 알고리즘은 연속된 작은따옴표와 문자열의 시작과 끝 부분에 있는 작은따옴표를 처리할 때 효율성이 떨어지지만 매우 안정적이고 구현이 매우 간단합니다.
1 다른 언어의 작은따옴표는 일반적으로 완전히 문자 그대로는 아닙니다(적어도 일반적으로 제한된 백슬래시 이스케이프를 허용합니다). 이것이 바로 생성할 인용 형식에 대한 모든 인용 규칙을 이해하는 것이 중요한 이유입니다(즉, 인용된 텍스트가 어떤 언어/문맥에서 사용될 것인지).
printf %q
다음은 로컬에 설치된 셸의 몇 가지 예 입니다 .
for s in /bin/ksh {,/opt/local}/bin/bash {,/opt/local}/bin/zsh
do
"$s" --version | head -1
"$s" -c 'printf "%q\n" "$@"' - \$sad\$test \'mixed\ quotes\" back\`tick
echo
done
산출:
version sh (AT&T Research) 1993-12-28 s+
'$sad$test'
$'\'mixed quotes"'
'back`tick'
GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin10.0)
\$sad\$test
\'mixed\ quotes\"
back\`tick
GNU bash, version 4.2.10(2)-release (i386-apple-darwin10.7.0)
\$sad\$test
\'mixed\ quotes\"
back\`tick
zsh 4.3.9 (i386-apple-darwin10.0)
\$sad\$test
\'mixed\ quotes\"
back\`tick
zsh 4.3.12 (i386-apple-darwin10.7.0)
\$sad\$test
\'mixed\ quotes\"
back\`tick
우리는 봤다케시작은 따옴표로 인용하는 것을 "선호"하는 것으로 보이며 $''
어떤 경우에는 이 형식을 사용합니다. 다른 쉘은 주로 백슬래시 이스케이프를 사용하는 것 같습니다(비록 $''
특정 문자가 있는 경우 이를 사용하지만).
답변2
작은따옴표로 묶습니다 \$sad\$test
.
$ echo $SHELL
/bin/bash
$ ./test.sh '\$sad\$test'
\$sad\$test
답변3
test.sh \$sad\$test
를 실행하면 test.sh
스크립트가 $sad$test
인수로 대신 수신됩니다 \$sad\$test
. 그 이유는 쉘이 \$
호출하기 전에 로 대체되기 때문입니다. 스크립트를 수신하려면 or를 수행해야 합니다.$
test.sh
\$sad\$test
test.sh '\$sad\$test'
test.sh "\\\$sad\\\$test"
다음과 같이 자신을 설득해 보세요.
function cat1stpar() {
cat << EOF
$1
EOF
}
cat1stpar \$sad\$test
cat1stpar '\$sad\$test'
cat1stpar "\\\$sad\\\$test"
또한 일반적으로 echo $1
사용하는 것은 위험합니다. 이렇게 하면:
./test.sh "aaa bbb"
./test.sh "aaa bbb"
출력은 다음과 같습니다:
aaa bbb
aaa bbb
아니다:
aaa bbb
aaa bbb
두 번째 출력을 원한다면 최소한 이 작업을 수행하여 echo "$1"
인수 echo
가 너무 많지 않고 하나의 인수를 받도록 해야 합니다.성격1. 전체 단어 토론을 보려면 Shell Man의 IFS 변수를 참조하세요.
어떤 사람들은 인쇄하기 전에 일부 문자를 변경하는 것보다 이것이 printf "%s\n" "$1"
더 안전하다고 말하지만 아직 완전히 이해하지는 못합니다.echo "$1"
echo
편집하다:
캐릭터 변경 에 관해서는 echo
그냥 이해합니다. 노력하다:
echo "-n"
printf "%s\n" "-n"
./test.sh "-n"
cat1stpar "-n"
답변4
스크립트에서:
echo "${1//$/\\$}"
이는 쉘에 내장된 간단한 문자열 대체입니다. 이 구문은 ${[VARIABLE_NAME]//[PATTERN]/[REPLACEMENT]}
전역 리터럴 문자열 대체에 사용됩니다.
왜 이 일을 하려는지 모르겠습니다. 스크립트는 실제로 사용자가 보낸 문자열을 보고합니다. \$sad\$test
결과는 '$sad$test'
작은따옴표를 사용하여 이스케이프된다는 점을 제외하면 정확히 동일한 문자열로 평가됩니다 $
.