bash 교체를 사용하여 문자열에서 이스케이프된 리터럴 기호를 모두 얻는 방법

bash 교체를 사용하여 문자열에서 이스케이프된 리터럴 기호를 모두 얻는 방법

현재 수행 중인 문자열에서 이스케이프된 리터럴만 반환할 수 있기를 원합니다.

foo="\'\"\(foobar\)'another'[program]\[\$var\]()"
echo "${foo//[^\\\']/}"

그러나 다음과 같이 출력됩니다.

\'\\''\\

원하는 출력은 다음과 같아야 합니다.

\'\"\(\)\[\$\]

나는 여전히 문자 그대로의 작은 따옴표를 얻으려고 노력하는 단계에 있지만 어떻게 든 작동하지 않거나 bash 확장에서 실제로 가능합니까?

편집하다

문자열은 bash $READLINE_LINE에서 나오므로 큰따옴표에 대한 삼중 백슬래시와 같은 추가 이스케이프가 없습니다.

답변1

변수를 리터럴 값으로 설정

\'\"\(foobar\)'another'[program]\[\$var\]()

큰따옴표로 묶인 문자열을 사용하면 각 리터럴 백슬래시를 이스케이프 처리해야 합니다.그리고그렇지 않으면 각각의 큰따옴표 또는 달러 기호가 확장을 트리거합니다.

string="\\'\\\"\\(foobar\\)'another'[program]\\[\\\$var\\]()"

작은따옴표로 묶인 문자열을 사용하는 경우 작은따옴표 삽입에만 주의하면 됩니다.

string='\'"'"'\"\(foobar\)'"'"'another'"'"'[program]\[\$var\]()'

여기에서는 각 작은 따옴표에 대해 큰 따옴표를 작은 따옴표에 추가하여 작은 따옴표 문자열을 나누기로 선택했습니다 '"'"'. 작은따옴표로 묶인 문자열 외부에서 이스케이프된 작은따옴표를 사용할 수도 있습니다 '\''.

인용이 너무 번거롭다면 여기에서 참조 문서를 사용하도록 선택할 수도 있습니다.

string=$( cat <<'END'
\'\"\(foobar\)'another'[program]\[\$var\]()
END
)

개행 문자가 문자열의 마지막 문자인 경우 후행 개행 문자가 잘립니다.

그런 다음 코드가 시도합니다.삭제모든 백슬래시와 작은따옴표는 올바르지 않은 것 같습니다. 대신 몇 가지 도구를 사용하세요.정제\그리고 다음 문자의 모든 인스턴스:

grep -o '\\.' <<<"$string"

이것은 생산할 것입니다

\'
\"
\(
\)
\[
\$
\]

또는,

grep -o '\\.' <<<"$string" | paste -s -d '\0' -

질문의 출력을 정확하게 재현하십시오.

bash루프에서 직접 이 작업을 수행할 수도 있습니다.

while [[ $string =~ \\. ]]; do
    printf '%s\n' "${BASH_REMATCH[0]}"
    string=${string#*\\?}
done

또는,

while [[ $string =~ '\'. ]]; do
    printf '%s\n' "${BASH_REMATCH[0]}"
    string=${string#*'\'?}
done

string이러한 일련의 문자가 문자열에 존재할 때마다 백슬래시 및 기타 문자의 다음 일치 비트까지 잘라내어 값이 수정됩니다. 각 반복에서 주어진 정규식과 일치하는 비트가 인쇄됩니다.

답변2

zsh대신 을 사용하면 bash다음을 수행할 수 있습니다.

set -o extendedglob
print -r -- ${foo//(#b)((\\?)|?)/$match[2]}

또는 다음을 사용하여 ksh93:

print -r -- "${foo//@(@(\\?)|@(?))/\2}"

(그것도 작동해야 한다고 생각 print -r -- "${foo//@(@(\\?)|?)/\2}"하지만 그렇지 않습니다.실수)

그리고 fish:

string join '' (string match -ar '\\\\.' $foo)

답변3

현재 문자를 삭제할지 여부를 알기 위해서는 이전 문자를 살펴봐야 하기 때문에 패턴 교체 작업을 사용하여 이러한 문자열을 찾을 수는 없다고 생각합니다. 이를 수행하려면 Perl의 정규식 부정적인 LookBehind와 같은 것이 필요합니다. \\x첫 번째 백슬래시가 두 번째 백슬래시를 이스케이프해야 하지만 두 번째 백슬래시는 그렇지 않아야 합니다 x. 적어도 정의가 일반적으로 작용하는 범위 내에서 백슬래시가 이스케이프되는 경우 이와 같은 문자열을 고려하면 훨씬 더 어렵습니다.

루프에서 일치하는 부분을 찾는 것이 더 쉬울 것이지만 Bash는 이를 매우 쉽게 만듭니다. (정규식 일치 연산자가 있으며 [[ text =~ re ]]일치 항목을 에서 찾을 수 있지만 ${BASH_REMATCH[@]}수동 이외의 여러 히트를 반복하는 방법은 없다고 생각합니다.)

하지만 grep예를 들어 다음을 사용하여 이 작업을 수행할 수 있습니다. 예를 들어, 다음은 한 줄에 하나씩 일련의 일치 항목을 출력합니다.

foo="\'\\\"\(foobar\)'another'[program]\[\$var\]()"
echo "$foo" | grep -oe '\\.'

그런 다음 출력을 파이프하여 tr -d '\n'개행 문자를 제거합니다. 또는 셸에서 처리해야 하는 경우 사용하세요. while IFS= read -r line; do...하지만 그렇게 하려면 다른 도구를 사용해야 합니다. 셸은 텍스트 처리에 적합하지 않습니다.

관련 정보