4.4의 변경 사항을 이스케이프 처리하는 bash 견적

4.4의 변경 사항을 이스케이프 처리하는 bash 견적

저는 임베디드 플랫폼의 bash를 4.1.9에서 최신 버전(4.4.12)으로 업데이트하고 있으며 이스케이프된 인수를 스크립트에 전달하는 이 간단한 시나리오에서 동작의 변화를 확인하고 있습니다.

스크립트/tmp/printarg:

#! /bin/sh
echo "ARG |$*|"

나는 다음과 같이 스크립트를 호출합니다.

bash -c "/tmp/printarg \\"abc\\""

나는 bash 4.3.42를 실행하는 여러 플랫폼(기본 x86_64 Linux)과 bash 4.1.9 및 4.2.37을 실행하는 여러 임베디드 플랫폼(ARM 및 PPC)에서 이 작업을 시도했는데 모두 예상한 결과를 얻었습니다.

38$ bash -c "/tmp/printarg \\"abc\\""
ARG |abc|

그러나 bash 4.4.12(네이티브 X86 또는 임베디드 플랫폼)를 사용하여 이 명령을 실행하면 다음과 같은 결과가 나타납니다.

$ bash -c "/tmp/printarg \\"abc\\""
ARG |abc\|            <<< trailing backslash

명령줄에서 두 번째 이스케이프된 따옴표와 닫는 따옴표 사이에 공백을 추가하면 더 이상 추가 백슬래시가 표시되지 않습니다.

$ bash -c "/tmp/printarg \\"abc\\" "
ARG |abc |            <<< trailing space, but backslash is gone

마치 고향에 온 것 같은 느낌이에요. 어떤 아이디어가 있나요? 또한 다양한 호환 옵션(compat40, compat41, compat42, compat43)을 활성화하도록 변경해 보았습니다.

답변1

bash -c "/tmp/printargs \\"abc\\""

당신이 원하는 것에서 도망칠 수 없습니다. 백슬래시 - 백슬래시는 이스케이프된 백슬래시이며 호출 셸에서 처리됩니다. 따라서 다음을 실행하는 것과 같습니다.

/tmp/printargs \abc\

큰따옴표는 다음과 같기 때문입니다.아니요탈출했습니다. 다음과 같이 작성할 수 있습니다.

bash -c '/tmp/printargs \abc\'

나는 당신이 실제로 원하는 것 같아요 :

bash -c "/tmp/printargs \"abc\""

bash -c에 인용된 "abc"를 전달하여 큰따옴표를 이스케이프합니다.

(당신이 보고 있는 다른 동작은 다른 버전의 bash가 입력 끝에서 이스케이프된 모든 것을 다르게 처리한다는 것입니다.)

printargs의 Perl 버전(동작이 약간 개선됨):

#!/usr/bin/perl
use feature qw(say);

for (my $i = 0; $i < @ARGV; ++$i) {
        say "$i: |$ARGV[$i]|";
}

답변2

bash -c "/tmp/printargs \\"abc\\""

이것이 당신이 원하는 일이라고 확신합니까? 명령을 효과적으로 실행 하면 set -x명령 실행이 다음과 같이 표시됩니다.

bash -c '/tmp/printargs \abc\'

즉, 백슬래시로 끝나는 문자열을 셸에 전달합니다. 첫 번째 따옴표 붙은 문자열에는 이스케이프된 백슬래시가 포함되고, 그 뒤에는 따옴표가 없는 abc이스케이프된 백슬래시와 따옴표로 묶인 빈 문자열이 차례로 포함됩니다. (Stackexchange의 완성된 구문 강조 표시가 abc따옴표 해제를 어떻게 표시하는지 참고하세요.)

끝에 따옴표 없이 백슬래시를 입력하는 것은 의미가 없습니다. 백슬래시는 다음 문자를 이스케이프하거나 아래와 같이 다음 개행 문자와 함께 제거되는 연속 줄을 시작할 수 있습니다.

$ bash -c $'echo "foo\\\nbar"'                                                                                                              
foobar 

이 경우에는 둘 다 없습니다. 다음 중 하나를 수행하려고 할 수 있습니다.

bash -c "/tmp/printargs \"abc\""
bash -c '/tmp/printargs "abc"'

둘 다 출력을 생성합니다 ARG |abc|.


더 간단한 테스트를 통해 쉘 간의 차이점을 확인할 수 있습니다.

$ bash -c 'echo $BASH_VERSION; echo abc\'
4.4.12(1)-release
abc\

$ ./bash -c 'echo $BASH_VERSION; echo abc\'
4.3.30(1)-release
abc

$ dpkg -l dash |grep ^i
ii  dash           0.5.8-2.4    amd64        POSIX-compliant shell
$ dash -c 'echo abc\'
abc\

$ dpkg -l zsh |grep ^i
ii  zsh            5.3.1-4+b2   amd64        shell with lots of features
$ zsh -c 'echo abc\'
abc

추측해야 한다면 다음에서 변경의 원인을 찾기 시작할 것입니다.

이 문서에서는 bash-4.4-alpha 버전과 bash-4.4-alpha 간의 변경 사항을 자세히 설명합니다.
이전 버전, bash-4.3-release.

1. Bash의 변경 사항

cccc. 읽을 때 평가가 중단되는 버그를 수정했습니다.
      따옴표가 없는 백슬래시로 끝나는 문자열에서 또는 소싱할 때 명령
      따옴표가 없는 백슬래시로 끝나는 파일.

답변3

이것을 설명하겠습니다.

$ bash -c "/tmp/quotefail \\"abc\\" "
ARG |abc |            <<< trailing space, but backquote is gone

@ilkkachu가 설명했듯이 set -x이것이 어떻게 설명되는지 살펴보겠습니다.

+ bash -c '/tmp/quotefail \abc\ '

물론 "\a"는 "a"이고 "\"는 ""이므로 /tmp/quotefail에서 수신한 매개변수는 "abc"이고 결과는 다음과 같습니다.

ARG |abc |

첫 번째 테스트에서는 백슬래시 뒤에 아무 것도 나오지 않으므로 여전히 백슬래시입니다.

관련 정보