두 번째 패턴 이전에 하나의 패턴을 바꾸는 경우 - 두 패턴 사이에 문자열을 유지합니다.

두 번째 패턴 이전에 하나의 패턴을 바꾸는 경우 - 두 패턴 사이에 문자열을 유지합니다.

이것은 내 코드입니다.

printf '%s' '{$aaa} \\{$bbb} \{$ccc}  {$ddd' | sed -r -e 's/(^|[^\\])\{\$/\1\$\{/g' -e 's/\\\\\{\$/\\\\\$\{/g'

결과:

${aaa} \\${bbb} \{$ccc} ${ddd

{$ddd닫는 괄호로 끝나지 않기 때문에 교체하면 안되는 마지막 패턴을 제외하면 결과는 정상입니다 }.

sed를 사용하여 이 작업을 어떻게 수행할 수 있나요?

또한 두 가지 실제 표현을 결합하는 방법을 알고 있다면 환영합니다(나에게는 그다지 중요하지 않음).

편집: 괄호도 다음 ($foo)과 같은 작업을 수행합니다.$(foo)

답변1

첫 번째 작업부터 시작하여 닫기까지만 변경을 수행합니다 {}.

printf '%s' '{$aaa} \\{$bbb} \{$ccc}  {$ddd' | sed 's/{$\([^}]*\)}/${\1}/g'

즉, {$끝부터 끝까지의 모든 내용이 } 에 배치되므로 \(\)대체 문자열에서 이를 역참조할 수 있습니다 \1. 산출:

${aaa} \\${bbb} \${ccc}  {$ddd

이제 백슬래시 이스케이프에 대해 설명합니다. 귀하의 솔루션은 \{$aaa}(만지지 마세요) 및 \\{$aaa}(교체) 에 효과적 이지만 무엇입니까 \\\{$aaa}? 바람직하지 않은 변경을 수행하게 됩니다.

따라서 먼저 모든 이중 백슬래시를 제거하는 것이 좋습니다. 예를 들어, 문자열의 일부가 될 수 없는 문자 조합으로 대체 #1하고 결국 다시 변경합니다. 이렇게 하면 단일 백슬래시에만 집중할 수 있습니다.

printf '%s' '{$aaa} \\{$bbb} \{$ccc} \\\{$eee} {$ddd' | sed 's/\\\\/#1/g;s/{$\([^}]*\)}/${\1}/g;s/#1/\\\\/g'

마지막으로 이를 제거하기 위해 마지막에 다음 \{으로 변경하고 다시 교체할 수 있습니다 .#2

printf '%s' '{$aaa} \\{$bbb} \{$ccc} \\\{$eee} {$ddd' | sed 's/\\\\/#1/g;s/\\{/#2/g;s/{$\([^}]*\)}/${\1}/g;s/#2/\\{/g;s/#1/\\\\/g'

결과:${aaa} \\${bbb} \{$ccc} \\\{$eee} {$ddd

이는 백슬래시 수에 관계없이 작동합니다.

하지만 #당신과 같은 캐릭터를 마음대로 사용할 수 없다면 어떨까요? 개행 문자는 줄의 일부가 될 수 없으므로 개행 문자를 사용할 수 있습니다. 당신은 GNU를 사용하고 있는 것 같으니 sed이렇게 할 수 있습니다.

printf '%s' '{$aaa} \\{$bbb} \{$ccc} \\\{$eee} {$ddd' | sed 's/\\\\/\n1/g;s/\\{/\n2/g;s/{$\([^}]*\)}/${\1}/g;s/\n2/\\{/g;s/\n1/\\\\/g'

POSIX에서 실행하려면 sed다음이 필요합니다.해결책

답변2

POSIX를 사용하면 sed다음과 같은 작업을 수행할 수 있습니다.

sed -e '
   # case for {$var}
   s/ \(\(\\\\\)\{0,\}\){\$\([^ }]*\)}/ \1${\3}/g
   s/^\(\(\\\\\)\{0,\}\){\$\([^ }]*\)}/\1${\3}/

   # case for ($var)
   s/ \(\(\\\\\)\{0,\}\)(\$\([^ )]*\))/ \1$(\3)/g
   s/^\(\(\\\\\)\{0,\}\)(\$\([^ )]*\))/\1$(\3)/
' input_file

공백이 파일의 유일한 공백이라고 가정합니다. 물론 TAB을 사용하여 문제를 해결하고 OP에 대한 연습으로 남겨둘 수 있습니다. 사용 가능한 확장을 사용하면 위의 내용을 더욱 단순화할 수 있지만 더 큰 적용성을 제공하는 솔루션을 GNU sed제공하고 싶습니다 .POSIX

관련 정보