에코가 내 인용 부호를 무시하는 이유는 무엇입니까?


24

echo명령은 내가 그것을 제공하는 전체 텍스트를 포함하지 않습니다. 예를 들어 내가 할 경우 :

   $ echo ' echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print $2}' `    '

출력합니다 :

echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk {print } `

'echo 명령에 포함 된 작은 따옴표 ( )는 포함되지 않습니다. 큰 따옴표로 전환하면 :

$ echo " echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print $2}' `  "

echo아무것도 출력하지 않습니다! 첫 번째 예제에서 작은 따옴표를 생략하고 두 번째 예제에서 아무것도 출력하지 않는 이유는 무엇입니까? 입력 한 내용을 정확하게 출력하려면 어떻게해야합니까?


3
여기서 달성하려는 것이 확실하지 않습니다. 하나의 반향 문을 다른 반점에 중첩시키는 이유는 무엇입니까? 아니면 문자 그대로 명령을 인쇄하려고합니까 (예를 들어 등)?
Andy Smith

에코 출력을 다른 파일에 삽입해야합니다

당신이하려는 일을 설명해야합니다. "다음 텍스트를 추가하고 싶습니다 : '…'파일에."
MikeyB

2
5 분 동안 이것을 편집하려고했지만 원하는 출력이 무엇인지 진지하게 알지 못합니다. 편집 : 좋아, 나는 지금 추측이 있다고 생각하므로 편집을 시도했다. 그것이 당신이 의도 한 것이 아니라면
Michael Mrozek

1
@Michael-와우-내가 당신에게 당신의 편집에 대한 몇 가지 담당자를 줄 수 있다면, 나는 정말 좋은 질문이 될 것입니다!
랜달

답변:


33

당신의 쉘은 따옴표에 도달하기 전에 '와를 모두 해석합니다 . 필자는 일반적으로 불필요하더라도 반박 할 인용 부호를 큰 따옴표로 묶습니다. 예를 들면 다음과 같습니다."echo

$ echo "Hello world"
Hello world

따라서 첫 번째 예에서 출력에 리터럴 따옴표를 포함하려면 이스케이프 처리해야합니다.

$ echo \'Hello world\'
'Hello world'

또는 이미 인용 된 인수 내에서 사용해야합니다 (그러나 동일한 종류의 인용 부호가 아니거나 어쨌든 탈출해야합니다).

$ echo "'Hello world'"
'Hello world'

$ echo '"Hello world"'
"Hello world"

두 번째 예에서는 문자열 중간에 명령 대체를 실행하고 있습니다.

grep  $ARG  /var/tmp/setfile  | awk {print $2}

로 시작하는 $것은 또한 쉘에 의해 특별히 처리됩니다-변수로 취급하고 값으로 대체합니다. 이러한 변수 중 어느 것도 쉘에 설정되어 있지 않기 때문에 실제로는 실제로 실행됩니다.

grep /var/tmp/setfile | awk {print}

grep하나의 인수 만 보이 므로 인수는 찾고있는 패턴이고 데이터를 읽어야하는 장소는 stdin이라고 가정하므로 입력 대기를 차단합니다. 그래서 두 번째 명령이 중단되는 것처럼 보입니다.

인수를 작은 따옴표로 묶는 경우 (이것은 첫 번째 예제가 거의 효과가 있었던 경우) 발생하지 않으므로 원하는 출력을 얻는 한 가지 방법입니다.

echo \'' echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print $2}' `    '\'

또한 큰 따옴표를 사용할 수 있지만 $셸 을 이스케이프 처리 하여 쉘이 변수로 해석하지 못하도록하고 백틱을 지정하면 셸에서 명령 대체를 즉시 실행하지 않습니다.

echo "' echo PARAM=\`  grep  \$ARG  /var/tmp/setfile  | awk '{print \$2}' \`    '"

7

Michael Mrozek의 답변 이 이것을 잘 다루기 때문에 귀하의 시도가 왜 그렇게 행동하는지에 대해서는 자세히 설명하지 않겠습니다 . 간단히 말해서, 작은 따옴표 사이의 모든 ( '…') 문자 (첫 번째, 특히 해석 '마크 리터럴 문자열의 끝) 반면, `$사이에 자신의 특별한 의미를 유지 "…".

작은 따옴표 안에 따옴표가 없으므로 작은 따옴표로 묶은 문자열 안에 작은 따옴표를 넣을 수 없습니다. 그러나 다음과 같은 관용구가 있습니다.

echo 'foo'\''bar'

이 인쇄는 foo'bar인수가 있기 때문에, echo단일 인용 세 문자열 구성되어 foo단일 문자와 연결, '(문자를 보호하여 얻은 '이전을 통해 특별한 의미에서 \단일 인용 세 문자열와 연결) bar. 따라서이면에서 일어나는 일은 아니지만 '\'', 작은 따옴표로 묶은 문자열 안에 작은 따옴표를 포함시키는 방법으로 생각할 수 있습니다 .

복잡한 여러 줄 문자열을 인쇄하려면 here document 가 더 좋습니다 . here 문서는 두 문자로 구성됩니다<<<<EOF, 다음 과 같은 마커 , 텍스트 라인, 끝 마커만으로 구성됩니다. 마커가 어떤 식 으로든 ( 'EOF'또는 "EOF"또는 \EOF'E ""OF'또는 ...) 따옴표로 묶인 경우 텍스트는 문자 그대로 해석됩니다 ( '일반 문자를 제외하고 작은 따옴표 내부와 같이 ). 마커가 전혀 인용되지 않은 경우 텍스트는 큰 따옴표로 표시된 것처럼 $\`특수 상태 를 유지하면서 "해석됩니다 (그러나 개행은 문자 그대로 해석 됨).

cat <<'EOF'
echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print $2}' `
EOF

1

좋아, 이것은 작동합니다 :-

echo ' echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '\''{print $2}'\'' `    '

여기에서 테스트하십시오 :-

[asmith@yagi ~]$ echo ' echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '\''{print $2}'\'' `    '
 echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print $2}' ` 

0

here 문서 사용에 대한 Gilles의 제안 은 정말 좋으며 Perl과 같은 스크립팅 언어에서도 작동합니다. OP 문제에 대한 그의 답변을 바탕으로 한 구체적인 예로서,

use strict;
my $cmd = q#cat <<'EOF' # . "\n" .
          q#echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print $2}' `# . "\n" .
          q#EOF# ;
open (my $OUTPUT, "$cmd |");
print $_ while <$OUTPUT>;
close $OUTPUT;

물론,이 예제는 약간 고안되었지만 SQL 문을 psql대신 보내는 데 유용한 기술이라는 것을 알았습니다.cat .

(알파벳이 아닌 비 공백 문자는 위의 #일반 인용 구문 에서 대신 사용될 수 있지만 해시는이 예제에서 잘 드러난 것처럼 보이며 주석으로 처리 되지 않습니다 .)


-1

당신의 명령을 보자

$ echo ' echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print $2}' `    '

따옴표없는 공백을 구분 기호로 사용하여 먼저 단어로 나눕니다.

Arg[1]=“' echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print”
Arg[2]=“$2}' `    '”

다음으로, 우리는 매개 변수 확장을 수행 확장 $…이 아닌 내부 '…'. $2비어 있기 때문에 (예 :를 통해 설정하지 않은 경우 set -- …) 빈 문자열로 바뀝니다.

Arg[1]=“' echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print”
Arg[2]=“}' `    '”

다음으로 따옴표 제거를 수행하십시오.

Arg[1]=“ echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk {print”
Arg[2]=“} `    ”

이러한 인수는 에코로 전달되어 단일 공백으로 구분되어 차례로 인쇄합니다.

“ echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk {print } `    ”

이 단계별 지침으로 관찰 된 동작이 더 명확 해지기를 바랍니다. 이 문제를 피하려면 다음과 같이 작은 따옴표를 이스케이프하십시오.

$ echo ' echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '\''{print $2}'\'' `    '

작은 따옴표로 묶인 문자열을 종료 한 다음 단어에 (이스케이프 된) 작은 따옴표를 추가 한 다음 단어를 구분하지 않고 새로운 작은 따옴표로 묶인 문자열을 시작합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.