sed - 필요한 경우 따옴표를 사용하도록 값을 바꿉니다.

sed - 필요한 경우 따옴표를 사용하도록 값을 바꿉니다.

100개가 넘는 jinja 템플릿 파일이 있고 "value: ..." 문자열이 각 파일에 0-k번 나타납니다. 문제는 일부 파일이 다음을 사용하고 있다는 것입니다.

value: something

그 중 일부는 다음과 같습니다:

value: 'something'

그들 중 일부:

value: "some other thing"

큰따옴표를 사용하여 모두 동일하게 보이도록 해야 합니다. 나는 이 작업을 수행하기 위해 sed를 사용할 것이라고 생각합니다.

sed -i 's/value: ['"]?(.*)['"]?/value: "\1"/g' *.j2

하지만 보시다시피 저는 sed를 너무 싫어해서 지난 2시간 동안 종료되지 않은 "s" 명령 등과 같은 무의미한 오류 메시지로 키보드를 파괴하고 싶었습니다.

입력 예:

- param:
  name: Command
  type: String
  value: '/bin/echo'
- param:
  name: Args
  type: String
  value: Hello World
- param:
  name: Something
  type: EnvVar
  value: "PATH"

이것으로부터 나는 다음을 얻어야 합니다:

- param:
  name: Command
  type: String
  value: "/bin/echo"
- param:
  name: Args
  type: String
  value: "Hello World"
- param:
  name: Something
  type: EnvVar
  value: "PATH"

답변1

"'표현식에 두 가지 형태의 따옴표()를 모두 사용해야 하면 상황이 까다로워집니다. 먼저, 초기 시도에서 쉘은 이를 's/value: ['인용된 문자열로 식별합니다. 후자의 인용문은 보존되지 않습니다.

이러한 경우에는 걱정할 필요가 없습니다. Sed 명령을 파일에 넣으면 됩니다. 그 내용은 쉘 조작의 대상이 되지 않습니다.

quotes.sed:

# (1) If line matches this regex (value: '), 
# (2) substitute the first ' with " and
# (3) substitute the ' in the end-of-line with ".
/value: '/{
  s/'/"/
  s/'$/"/
}
# (4) If line matches this regex (value: [^"]), 
# (5) substitute :<space> for :<space>" and
# (6) append a " in the end-of-line.
/value: [^"]/{
  s/: /: "/
  s/$/"/
}
$ sed -Ef quotes.sed file
- param:
  name: Command
  type: String
  value: "/bin/echo"
- param:
  name: Args
  type: String
  value: "Hello World"
- param:
  name: Something
  type: EnvVar
  value: "PATH"

답변2

통화 sed에 두 가지 문제가 있습니다.

  • 작은따옴표로 묶인 프로그램에서는 ['"]정규식의 일부로 리터럴 작은따옴표를 포함합니다. sed작은따옴표 안의 작은따옴표는 이스케이프할 수 없기 때문에 작동하지 않습니다. 그러나 로 표현할 수 있습니다 \x27.
  • ... (.*) ...구문은 확장된 정규식 구문 (이며 )기본적으로 "그룹 캡처"를 의미합니다. -E옵션을 사용 sed하거나 캡처 그룹을 \(.*\)사용 하여 정의해야 합니다.기본 정규식?(그러나 비슷한 것으로 교체 해야 합니다 \{0,1\}.)

내 테스트에서는 다음이 작동합니다.

sed -E 's/value: [\x27"]?([^\x27"]*)[\x27"]?/value: "\1"/' input.j2

답변3

GNU awk를 사용하여 match() 및 gensub()에 세 번째 인수를 전달합니다.

$ awk 'match($0,/(\s*value:\s*)(.*)/,a){$0=a[1] "\"" gensub(/[\047"]/,"","g",a[2]) "\""} 1' file
- param:
  name: Command
  type: String
  value: "/bin/echo"
- param:
  name: Args
  type: String
  value: "Hello World"
- param:
  name: Something
  type: EnvVar
  value: "PATH"

그렇지 않으면 awk를 사용하십시오.

$ awk '/value:/{hd=$0; sub(/:.*/,": ",hd); gsub(/[^:]*: *[\047"]?|[\047"]$/,"");  $0=hd "\"" $0 "\""} 1' file
- param:
  name: Command
  type: String
  value: "/bin/echo"
- param:
  name: Args
  type: String
  value: "Hello World"
- param:
  name: Something
  type: EnvVar
  value: "PATH"

답변4

Raku(이전 Perl6) 사용

Larry Wall이라는 신사가 "perl6-users" 메일링 리스트에 이 깔끔한 인용 팁을 올렸습니다.[이메일 보호됨]). 아래 NNTP 링크의 팁 #8을 참조하세요.

~$ env re="\'" raku -ne 'say $0 if m/ <?after value\:\s >  \"? <{ %*ENV<re> }>?  (.+?) \"? <{ %*ENV<re> }>? $$ /;'  jinja.txt
「/bin/echo」
「Hello World」
「PATH」

위의 코드는 올바른 일치를 보여줍니다. 따라서 필요한 것은 다음 코드를 실행하는 것뿐입니다.

~$ env re="\'" raku -pe 's/ <?after value\:\s >  \"? <{ %*ENV<re> }>?  (.+?) \"? <{ %*ENV<re> }>? $$ /"{$0}"/;'  jinja.txt
- param:
  name: Command
  type: String
  value: "/bin/echo"
- param:
  name: Args
  type: String
  value: "Hello World"
- param:
  name: Something
  type: EnvVar
  value: "PATH"

탈출을 더 읽기 쉽게 만들고 싶습니까? 위와 같은 ENV 변수를 사용하고 싶지 않으신가요? 그런 다음 인용 문자의 철자를 입력하세요(아래 NNTP 링크의 Larry Wall의 팁 #8에서도 참조).

~$ raku -ne 'say $0 if m/ <?after value\:\s >  \c[QUOTATION MARK]? \c[APOSTROPHE]?  (.+?)  \c[APOSTROPHE]? \c[QUOTATION MARK]? $$ /;'  jinja.txt
「/bin/echo」
「Hello World」
「PATH」

~$ raku -pe 's/ <?after value\:\s >  \c[QUOTATION MARK]? \c[APOSTROPHE]?  (.+?)  \c[APOSTROPHE]? \c[QUOTATION MARK]? $$ /"{$0}"/;'  jinja.txt
- param:
  name: Command
  type: String
  value: "/bin/echo"
- param:
  name: Args
  type: String
  value: "Hello World"
- param:
  name: Something
  type: EnvVar
  value: "PATH"

HTH.

https://raku.org/
https://www.nntp.perl.org/group/perl.perl6.users/2020/07/msg9004.html

관련 정보