줄 바꿈으로 구분된 여러 단락 중 하나의 주석 처리를 제거하려면 어떻게 해야 합니까?

줄 바꿈으로 구분된 여러 단락 중 하나의 주석 처리를 제거하려면 어떻게 해야 합니까?

설명: GNU sed를 사용합니다.

현재 상황 - ~/.screenrc, 마지막 몇 줄:

# name synthpop
# screen -t script emacs -nw /home/$USER/bin/synthpop

# name thrashmetal
# screen -t script emacs -nw /home/$USER/bin/thrashmetal
# number 1
# split -v
# focus
# chdir "/home/$USER/thrashmetal/src"
# screen -t scr watch nl asdkjlek.html
# number 2
# focus
# split
# focus
# screen -t output watch thrashmetal asdkjlek.html
# number 3
# focus
# split
# focus
# chdir "/home/$USER/thrashmetal/plan"
# screen -t soll watch less soll
# number 4
# focus

# name darkwave
# screen -t script emacs -nw /home/$USER/bin/darkwave

목적:

# name synthpop
# screen -t script emacs -nw /home/$USER/bin/synthpop

name thrashmetal
screen -t script emacs -nw /home/$USER/bin/thrashmetal
number 1
split -v
focus
chdir "/home/$USER/thrashmetal/src"
screen -t scr watch nl asdkjlek.html
number 2
focus
split
focus
screen -t output watch thrashmetal asdkjlek.html
number 3
focus
split
focus
chdir "/home/$USER/thrashmetal/plan"
screen -t soll watch less soll
number 4
focus

# name darkwave
# screen -t script emacs -nw /home/$USER/bin/darkwave

현재 시도는 거의 성공했지만 다음 줄이 나타나면 멈추지 않을 것입니다. 이 줄은 주석 기호나 영숫자 문자가 없는 새로운 줄입니다.

sed 's+^# \(name thrashmetal\)+\1+;:a;s+# ++;ta' .screenrc

설명, 의도:

  • '일련의 할 일의 시작

  • s바꾸다

  • +"+"를 구분 기호로 사용하세요.

  • # …"#"으로 시작하는 줄을 찾을 때까지 한 줄씩 살펴보세요...

  • \(나중에 참조할 수 있도록 그룹 시작

  • name thrashmetal그리고 "스래시메탈 이름"으로 계속하세요.

  • \)그룹 끝

  • +\1+줄의 첫 번째 항목을 "#" 없이 그룹 부분으로 바꿉니다.

  • ;그리고 그 시점부터 다른 일을 하세요...

  • :a"a"라는 루프를 만드세요.

  • ;s각 후속 라인에 대해 한 줄씩 교체합니다...

  • +"+"를 구분 기호로 설정

  • #줄에서 그 뒤에 오는 내용에 관계없이 줄에서 "#"이 처음으로 나타나는 경우...

  • ++아무것도 없습니다. 효과적으로 삭제하세요.

  • ;ta실패하면 그냥 해라단락 끝에 도달하면 스래시메탈 블록과 다크웨이브 블록을 구분하는 두 줄이 끊어집니다., 그런 다음 "a"의 위치로 돌아갑니다.

  • '일련의 할 일이 끝났습니다.

  • .screenrc내 현재 디렉터리(내 홈 디렉터리)에 있는 ".screenrc" 파일에 대해 일련의 작업을 수행합니다.

표준 출력:

# name synthpop
# screen -t script emacs -nw /home/$USER/bin/synthpop

name thrashmetal
screen -t script emacs -nw /home/$USER/bin/thrashmetal
number 1
split -v
focus
chdir "/home/$USER/thrashmetal/src"
screen -t scr watch nl asdkjlek.html
number 2
focus
split
focus
screen -t output watch thrashmetal asdkjlek.html
number 3
focus
split
focus
chdir "/home/$USER/thrashmetal/plan"
screen -t soll watch less soll
number 4
focus

name darkwave
screen -t script emacs -nw /home/$USER/bin/darkwave

이 문제를 해결하는 방법? 스래시메탈 단락 끝에 도달하자마자 루프가 멈추지 않고 단순히 다음 단락(darkwave 단락)으로 점프하여 계속되도록 하려면 제가 뭘 잘못하고 있는 걸까요?

내 생각엔, 그 루프에 있는 것이 무엇이든 틀림없이 잘못된 것 같아요... 아마도 "t"일 수도 있지만 "T"나 "b"도 잘리지 않을 것입니다...

답변1

sed '/^# name thrashmetal$/,/^$/ s/^# //' file

#그러면 범위의 각 줄에서 초기 및 후속 공백 문자가 제거되어 교체가 적용됩니다 .

범위는 줄 일치로 시작 ^# name thrashmetal$하고 첫 번째 후속 줄 일치 ^$(빈 줄)로 끝납니다.

또는 다음으로 직접 번역됩니다 awk.

awk '/^# name thrashmetal$/,/^$/ { sub(/^# /, "") }; 1' file

여기서 후행 1{ print $0 }또는 의 약자 { print }로서 현재(수정될 수 있는) 줄이 출력되도록 합니다(텍스트 인쇄는 sed스크립트에 암시적으로 적용됩니다).


편집자에 관심이 있는 사람이라면 ed다음 편집 명령을 사용하여 이 문제를 해결할 수 있습니다.

/^# name thrashmetal$/;.,/^$/ s/^# //

이렇게 하면 커서가 원하는 단락의 첫 번째 줄로 이동하고 빈 줄에 도달할 때까지 해당 줄과 모든 후속 줄에 대체 내용이 적용됩니다.

우리는 사용할 수 없습니다

/^# name thrashmetal$/,/^$/ s/^# //

...주소는 현재 줄을 기준으로 계산되고 현재 줄은 편집기를 시작할 때 파일 끝에 있기 때문입니다. 파일의 끝에 있기 때문에 주소가 /^$/시작 주소보다 앞선 줄이 되기 때문에 명령의 범위는 아무런 영향을 미치지 않습니다. (첫 번째 빈 줄은 현재 줄을 기준으로 문단의 시작 부분 앞에 있습니다.) .


자신만의 방법이 수정되었습니다(구분 기호를 더하기 기호에서 기본값으로 변경하고 여러 표현식으로 분할하여 이식성이 더 높음).

sed -e '/^# \(name thrashmetal\)/!b' -e 's//\1/' -e :a -e n -e 's/^# //' -e ta file

초기 교체를 수행하는 대신 단락의 첫 번째 줄 일치에 따라 나머지 편집 스크립트를 건너뛸지 여부가 결정됩니다. b해당 줄이 발견되지 않으면 건너뜁니다.

라인이 발견되면 이를 수정하고 레이블을 생성합니다 a. 그런 다음 현재 버퍼를 인쇄하고 그 내용을 다음 줄로 바꿉니다 n. 루프는 이전과 같이 계속되며, #버퍼의 내용이 변경되면 하위 문자열을 제거하고 레이블로 다시 루프합니다.

초기 시도의 주요 문제는 다음과 같습니다.

sed 's+^# \(name thrashmetal\)+\1+;:a;s+# ++;ta' .screenrc

..." a-loop"는 무조건적이므로 초기 교체의 성공 여부에 관계없이 입력된 모든 줄에 적용됩니다(처음 두 줄은 명령의 영향을 받지 않지만 복사-붙여넣기 오류인 것 같습니다). . 루프는 다음 줄도 읽지 않으므로 그냥 실행됩니다.한 번한 줄당( #한 줄에 두 개 이상의 하위 문자열이 발견되지 않는 한)

내 수정 사항은 초기 교체를 테스트와 교체로 나눈 다음 a교체가 실패할 때까지 "-loop"가 입력의 다음 줄을 읽는지 확인하는 것이었습니다. 또한 어떤 줄에서든 여러 개의 문자열이나 포함된(내부) 문자열을 바꾸지 않고 #줄 시작 부분의 첫 번째 문자열만 바꾸었습니다.

답변2

이 스크립트는 원하는 작업을 수행하는 것 같습니다.

H
/^$/ T show
$ T show
d

:show
x
s/\n//
/^# name thrashmetal/ {
  s/# //
  s/\n# /\n/g
}

우리는 효과적으로 빈 줄로 구분된 덩어리로 물건을 나눕니다. 로 시작하는 블록을 찾으면 line으로 시작하는 모든 문자열을 # name thrashmetal삭제합니다 #.

예제 입력이 주어지면 출력이 생성됩니다.

$ sed -f filter.sed < example.conf
# name synthpop
# screen -t script emacs -nw /home/$USER/bin/synthpop

name thrashmetal
screen -t script emacs -nw /home/$USER/bin/thrashmetal
number 1
split -v
focus
chdir "/home/$USER/thrashmetal/src"
screen -t scr watch nl asdkjlek.html
number 2
focus
split
focus
screen -t output watch thrashmetal asdkjlek.html
number 3
focus
split
focus
chdir "/home/$USER/thrashmetal/plan"
screen -t soll watch less soll
number 4
focus

# name darkwave
# screen -t script emacs -nw /home/$USER/bin/darkwave

주석이 달린 sed 스크립트:

# Append current line to the hold space
H

# If we find a blank line or reach EOF, print out the
# current chunk
/^$/ T show
$ T show

# Delete the current line (we'll print it later in the
# show routine)
d

:show
# Swap the pattern space and the hold space
x

# Remove the initial "\n" that was added when we appended
# the first line with the H command
s/\n//

# If this is our target chunk, remove the comments
/^# name thrashmetal/ {
  s/# //
  s/\n# /\n/g
}

답변3

awk 사용을 고려할 수도 있습니다.

$ awk -v RS= -v ORS='\n\n' '/thrashmetal/{sub(/^# /,"");gsub(/\n# /,"\n",$0)}1'  .screenrc
# name synthpop
# screen -t script emacs -nw /home/$USER/bin/synthpop 

name thrashmetal
screen -t script emacs -nw /home/$USER/bin/thrashmetal
number 1
split -v
focus
chdir "/home/$USER/thrashmetal/src"
screen -t scr watch nl asdkjlek.html
number 2
focus
split
focus
screen -t output watch thrashmetal asdkjlek.html
number 3
focus
split
focus
chdir "/home/$USER/thrashmetal/plan"
screen -t soll watch less soll
number 4
focus 

# name darkwave
# screen -t script emacs -nw /home/$USER/bin/darkwave 

여기서 RS(Input Record Separator)를 공백으로 설정하여 단락을 단일 행으로 처리할 수 있습니다.

답변4

사용행복하다(이전 Perl_6)

~$ raku -ne 'if / thrashmetal /fff^/ \# \s name / { .subst(/^ "\# " /).put } else { $_.put };'  file

또는:

~$ raku -ne 'put (/ thrashmetal /fff^/ \# \s name /) ?? $_.subst(/^ "\# " /)  !! $_ ;'  file

Raku는 Perl 계열의 프로그래밍 언어입니다. Raku -ne의 awk와 유사한 비자동 인쇄 명령줄 플래그와 if/else 문을 사용하여 선택한 줄을 변경할 수 있습니다.

여기서 핵심은 /…ON…/fffˆ/…OFF…/첫 번째 인식 필드가 일치하면 ON으로 바뀌고 두 번째 인식 필드가 일치하면 OFF로 바뀌는 Raku의 "트리거" 연산자를 사용하는 것입니다. 이를 기반으로 fff여기에 후행 ^캐럿을 추가하여 Raku에게 두 번째 일치하는 줄을 삭제하도록 지시합니다.

thrashmetal따라서 첫 번째 일치 항목과 \# \s name두 번째 일치 항목 모두에 대해 필수 주석 처리된 레코드/단락을 한 번에 일치시킬 수 있습니다 . 식별된 레코드의 주석 처리 제거를 사용하십시오 .subst(/^ "\# " /).

입력 예:

# name synthpop
# screen -t script emacs -nw /home/$USER/bin/synthpop

# name thrashmetal
# screen -t script emacs -nw /home/$USER/bin/thrashmetal
# number 1
# split -v
# focus
# chdir "/home/$USER/thrashmetal/src"
# screen -t scr watch nl asdkjlek.html
# number 2
# focus
# split
# focus
# screen -t output watch thrashmetal asdkjlek.html
# number 3
# focus
# split
# focus
# chdir "/home/$USER/thrashmetal/plan"
# screen -t soll watch less soll
# number 4
# focus

# name darkwave
# screen -t script emacs -nw /home/$USER/bin/darkwave

예제 출력:

# name synthpop
# screen -t script emacs -nw /home/$USER/bin/synthpop

name thrashmetal
screen -t script emacs -nw /home/$USER/bin/thrashmetal
number 1
split -v
focus
chdir "/home/$USER/thrashmetal/src"
screen -t scr watch nl asdkjlek.html
number 2
focus
split
focus
screen -t output watch thrashmetal asdkjlek.html
number 3
focus
split
focus
chdir "/home/$USER/thrashmetal/plan"
screen -t soll watch less soll
number 4
focus

# name darkwave
# screen -t script emacs -nw /home/$USER/bin/darkwave

https://docs.raku.org/routine/fff%5E
https://raku.org

관련 정보