sed: 성공을 조건으로 교체

sed: 성공을 조건으로 교체

sed나는 대체를 수행하고 성공 상태를 조건으로 사용하여 행을 인쇄하는 좋은 사용법을 발견했습니다 .

$ seq 3 | sed -n 's/2/B/ p'
B

이 짧은 형식을 확장하여 더 많은 작업을 수행할 수 있는지 궁금합니다. 좋다,

  • 이 줄은 교체가 성공한 경우에만 인쇄되지만,
  • 인쇄하기 전에 대체 작업을 더 수행해야 합니다.

가능합니까? 다음을 시도했지만 실패했습니다.

$ seq 3 | sed -n 's/2/B/ {p}'
sed: -e expression #1, char 8: unknown option to `s'

답변1

/2/더 복잡한 명령의 주소로 사용할 수 있습니다 .

sed -n '/2/ { s/2/B/; /BB/d; p; }'

이는 적어도 하나를 포함하는 줄에 대해 2첫 번째 발생을 2with 로 바꾼 다음 B(이 경우 이 대체는 s//B/"가장 최근에 일치한 표현식 사용"을 의미하는 빈 정규식으로 단축될 수도 있음) 줄을 삭제합니다. 하위 문자열이 포함되어 BB있으면 해당 행이 출력됩니다(삭제되지 않은 경우). 다른 라인은 전혀 출력되지 않습니다 -n.

당신은 또한 사용할 수 있습니다

sed -e '/2/!d' -e 'other commands'

그러면 이를 포함하지 않는 모든 행이 제거되고 나머지 행에 2적용 됩니다.other commands

각각 주어진 를 사용하는 여러 표현식을 사용하는 -e것은 입력 스트림에 일련의 명령을 적용하는 표준 방법입니다 sed. 대부분의 최신 sed구현에서는 구분된 표현식도 이해합니다 ;. GNU를 먼저 볼 sed필요는 없습니다 .;}

답변2

p이것은 명령의 표시 이지 명령 sed이 아닙니다 .p sed

어떤 작업을 수행하려면( p생성된 패턴 공간을 인쇄하거나 w파일에 쓰는 것( w명령과 함께 사용할 수 있는 또 다른 플래그 ) 외에) 대체 항목이 있는 경우 명령(또는 의 GNU 명령 )을 s사용할 수 있습니다. 아니요 ), 특정 레이블(또는 레이블이 없는 경우 끝 부분)로 분기하므로 다음을 수행할 수 있습니다.tTsed-T

GNU 특정:

sed -n 's/2/B/;T;=;p;#and other commands if there were substitutions'

좋다:

substitute(the first occurrence of 2 with B in the pattern space)
if (no substitution was made so far)
   goto(end)
print-pattern-space
print-input-line-number
: end

기준:

sed '
  s/2/B/;t more
  d
  :more
  p;=;#and other commands
'

또는 다음을 사용할 수 있습니다.

sed -n '/regexp/ { s//replacement/; p; =; }'

빈 정규식을 사용하면 이전 정규식(예: )이 재사용됩니다 ed.

답변3

"{ .... }"를 사용하여 명령을 그룹화할 수 있습니다. 일반적인 형태는 다음과 같습니다.

/<regexp>/ {
             cmd1
             cmd2
             ...
           }

여기서 "cmd"는 "s/.../.../"뿐만 아니라 "p", "q" 등과 같은 일반 sed 명령입니다. 명령이 정규식과 일치하는 모든 줄에 적용되는 "규칙"이라고 생각하세요. 정규식과 여는 중괄호 사이에 느낌표를 사용하여 규칙을 부정할 수도 있습니다. 이 경우 규칙은 모든 행에 적용됩니다.아니요정규식을 일치시킵니다.

다음은 스크립트 시작 부분부터 주석이 아닌 첫 번째 줄까지 모든 주석 전용 줄을 인쇄하는 예입니다.

sed '/^[[:blank:]]*#/ !{
                          q
                        }'

"#"으로 시작하는 모든 줄은 규칙과 일치하므로 그냥 인쇄됩니다(이를 억제하기 위해 "-n" 옵션을 사용하지 않았습니다). 정규식과 일치하지 않는 첫 번째 줄(실제로는 모든 줄이지만 실제로는 첫 번째 줄만 처리됨)은 단순히 sed를 종료하는 규칙을 트리거합니다.

그러나 규칙을 사용하는 것보다 더 강력한 또 다른 방법이 있습니다. 소위 "태그"를 정의하는 것입니다. GOTO와 같은 명령을 사용하여 기호 위치로 분기합니다. 작동 방식은 다음과 같습니다.

1) 무조건 분기 sed 스크립트는 다음과 같이 작동합니다. 입력의 첫 번째 줄을 읽은 다음 마지막 명령에 도달할 때까지 모든 sed 명령을 차례로 적용합니다(줄이 변경되면 변경된 줄에 추가 명령이 적용됩니다). "-n" 옵션을 사용하지 않으면 결과가 에 인쇄됩니다. 그래야만 다음 입력 줄을 읽고 마지막 입력 줄이 처리될 때까지 프로세스가 다시 시작됩니다.

현재 줄에 명령이 적용되는 순서를 변경하는 방법이 있습니다.

: [라벨]

명령 자체는 아무 작업도 수행하지 않지만 다른 명령을 사용하여 이 위치로 분기할 수 있습니다. BASIC과 "goto" 명령 같은 언어를 기억하시나요? 이는 후속 "goto"(유사) 명령이 이동할 수 있는 레이블을 표시합니다. 이전에 정의된 레이블로 분기되는 무조건 sed 명령은 다음과 같습니다.

b [레이블]

"b"는 "분기"를 의미합니다. ":" 명령을 사용하여 정의한 내용에 해당합니다. 레이블이 생략되면 실행은 스크립트 끝으로 분기됩니다.

예를 들면 다음과 같습니다. 프로그램을 얻었지만 불행하게도 코드 들여쓰기가 공백 대신 탭으로 이루어졌는데 이를 변경하고 싶습니다. 분명히 필요할 수 있으므로 코드 내의 탭이 아닌 코드 앞의 탭만 변경하고 싶을 것입니다. 불행하게도 정규식에는 이를 위한 직접적인 기능이 없으므로 직접 구현해야 합니다. 알고리즘은 다음과 같습니다. 한 줄이 다음 형식인 한공백 다음에 탭 문자가 옵니다.첫 번째 탭을 공백 8개로 변경하고 텍스트 앞에 탭이 없어질 때까지 같은 줄에서 반복합니다. 그래야만 선이 인쇄됩니다. 이 루프형 구조는 ":" 및 "b" 명령을 사용하여 설정됩니다. 여기서는 다양한 유형의 공백을 읽을 수 있도록 하기 위해 \b(공백) 및 \t(탭)을 사용하고 있습니다. 스크립트를 테스트할 때 실제 공백/탭으로 바꾸세요.

sed ':start
     /^\b*\t/ {
                s/^\(\b*\)\t/\1\b\b\b\b\b\b\b\b/
                b start
              }'

2) 조건 분기 이제 태그를 설정하고 분기하는 방법을 알았으므로 추가 변경 사항이 있습니다. 성공하기 전에 실행된 s/.../.../ 명령을 기반으로 해당 태그로 분기할 수 있습니다(즉, 무언가 변경됨을 의미함). 혹은 아무것도 아닌. 이를 수행하는 명령은 다음과 같습니다.

t [태그]

다음으로 분기

T [태그]

이것은 "t"의 부정적인 대응입니다. 만약에 분기한다아니요s 명령이 성공했습니다.

다음은 작동 방식에 대한 간단한 예입니다. 특별히 유용한 작업은 수행하지 않지만 원칙을 보여줍니다. sed 스크립트는 모든 입력의 첫 번째 줄만 허용합니다. 첫 번째 문자가 "a", "b" 또는 "c" 중 하나이면 "YES"를 인쇄하고, 그렇지 않으면 "NO"를 인쇄합니다.

sed -n 's/^[abc]/x/
        t yes
        b no
        :no
        s/^.*$/NO/p
        q
        :yes
        s/^.*$/YES/p
        q'

제어 흐름은 간단합니다. 먼저 대체를 시도하고 첫 번째 문자가 "a", "b" 또는 "c"인 경우 "x"로 변경합니다. 성공하면 분기 명령 "t yes"는 lael "yes"로 분기되어 전체 줄이 "YES"로 변경되고 sed가 종료됩니다("q" 명령). 이 교체가 실패하면 "t" 명령을 전달하고 "b" 명령을 실행하여 "no" 레이블로 점프합니다.

다양한 입력( echo "..." | sed <script>충분히 좋음)을 시도하여 작동 방식을 확인한 다음 "t" 명령을 "T"로 변경하고 결과에 미치는 영향을 확인하십시오.

답변4

그 이상의 작업이 필요한 경우 s/old/new/명확성, 견고성, 이식성, 유지 관리성 등의 조합을 위해 sed 대신 awk를 사용하는 것이 좋습니다.

$ seq 3 | awk 'sub(/2/,"B")'
B

$ seq 3 | awk 'sub(/2/,"B") { sub(/B/,"foo"); print }'
foo

관련 정보