설명: 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