특정 단어 뒤에 줄이 설정되지 않은 경우에만 줄을 추가하는 방법

특정 단어 뒤에 줄이 설정되지 않은 경우에만 줄을 추가하는 방법

다음 줄을 추가하기 위해 다음 sed cli를 빌드합니다.

force_https_protocol=PROTOCOL_TLSv1_2

줄 뒤에 :

[security]

sed CLI :

sed  -i '/\[security\]/a force_https_protocol=PROTOCOL_TLSv1_2'  /etc/ambari-agent/conf/ambari-agent.ini

하지만 문제는 - 라인이 force_https_protocol=PROTOCOL_TLSv1_2 이미 뒤에 있을 때입니다.[security]

라인이 이미 존재하는 경우 라인 추가를 무시하기 위해 sed 구문을 변경하는 방법은 무엇입니까?

예상 출력

[security]
force_https_protocol=PROTOCOL_TLSv1_2
keysdir=/var/lib/ambari-agent/keys
server_crt=ca.crt
passphrase_env_var_name=AMBARI_PASSPHRASE

잘못된 파일:

[security]
force_https_protocol=PROTOCOL_TLSv1_2
force_https_protocol=PROTOCOL_TLSv1_2
keysdir=/var/lib/ambari-agent/keys
server_crt=ca.crt
passphrase_env_var_name=AMBARI_PASSPHRASE

답변1

파일의 모든 "force_https_protocol=PROTOCOL_TLSv1_2"가 [security] 태그 내에 있고 다른 곳에 나타나지 않는다고 가정합니다.

sed -e '/^force_https_protocol=PROTOCOL_TLSv1_2$/d'\
    -e '/\[security\]/a force_https_protocol=PROTOCOL_TLSv1_2' file

아이디어는 "force_https_protocol=PROTOCOL_TLSv1_2" 문자열을 포함하는 파일의 모든 줄을 삭제하는 것입니다.

설명

/^force_https_protocol=PROTOCOL_TLSv1_2$/d'

"force_https_protocol=PROTOCOL_TLSv1_2" 문자열이 포함된 모든 줄을 삭제합니다.

테스트

$ cat file
[security]
force_https_protocol=PROTOCOL_TLSv1_2
keysdir=/var/lib/ambari-agent/keys
server_crt=ca.crt
passphrase_env_var_name=AMBARI_PASSPHRASE

[security]
keysdir=/var/lib/ambari-agent/keys
server_crt=ca.crt
passphrase_env_var_name=AMBARI_PASSPHRASE

$ sed -e '/^force_https_protocol=PROTOCOL_TLSv1_2$/d'\
      -e '/\[security\]/a force_https_protocol=PROTOCOL_TLSv1_2' file
[security]
force_https_protocol=PROTOCOL_TLSv1_2
keysdir=/var/lib/ambari-agent/keys
server_crt=ca.crt
passphrase_env_var_name=AMBARI_PASSPHRASE

[security]
force_https_protocol=PROTOCOL_TLSv1_2
keysdir=/var/lib/ambari-agent/keys
server_crt=ca.crt
passphrase_env_var_name=AMBARI_PASSPHRASE

답변2

1. AWK 사용

여기에 추가하는 보다 일반적인 문제에 대한 가능한 해결책이 있습니다.다음 경우에만 레이블이 지정된 텍스트 블록(예: 파일의 특정 레이블 뒤에 있고 다음 레이블 또는 파일의 시작 부분 앞에 오는 텍스트 줄)아직 존재하지 않습니다.

간단한 접근 방식은 파일을 뒤로 이동하여 마지막으로 만난 시간을 추적하는 것입니다., 특정 라벨을 만날 때마다(라벨 자체를 인쇄하기 직전) 인쇄하지만, 본 적이 없는 경우에만() 아직, 그런 일을 겪었다는 사실은 잊어버리세요() 라벨을 발견할 때마다. 그리고 물론 마지막 단계에서 결과를 반전시킵니다.

tac file | awk '
    /^force_https_protocol=PROTOCOL_TLSv1_2$/ {
        seen = 1
    }
    /^\[security\]$/ {
        if ( ! seen ) {
            print "force_https_protocol=PROTOCOL_TLSv1_2"
        }
    }
    /^\[[^]]*\]$/ {
        seen = 0
    }
    1' | tac

tac, 포함 된GNU Coreutils, 파일을 한 줄씩 연결하고 반전합니다. 다른/표준 도구를 사용하여 파일을 되돌리는 방법은 U&L의 여러 Q/A에서 다룹니다(예:sed '1!G;h;$!d' 명령은 어떻게 파일 내용을 반대로 바꾸나요?그리고역방향 잡기).

다음 텍스트 조각의 force_https_protocol=PROTOCOL_TLSv1_2첫 번째 조각 뒤에는 삽입되지 않습니다 .[security]

[security]
keysdir=/var/lib/ambari-agent/keys
force_https_protocol=PROTOCOL_TLSv1_2
passphrase_env_var_name=AMBARI_PASSPHRASE

[security]
...

간단히 삽입하려면라벨이 나타날 때마다이미 존재하는 경우 동일한 접근 방식으로 인해 다음이 발생할 수 있습니다.

tac file | awk '
    /^force_https_protocol=PROTOCOL_TLSv1_2$/ {
        seen = NR
    }
    /^\[security\]$/ {
        if ( ( NR == 1 ) || ! ( NR == seen + 1 ) ) {
            print "force_https_protocol=PROTOCOL_TLSv1_2"
        }
    }
    1' | tac

(이것~ 할 것이다위의 텍스트 샘플 force_https_protocol=PROTOCOL_TLSv1_2뒤에 삽입 ).[security]

2. sed 사용

sed다양한 주기를 사용할 수 있습니다 ( N;P;D;예: U&L의 다른 Q/A에서 자세히 다룹니다.여러 줄 문자열을 대체하기 위해 sed를 어떻게 사용할 수 있습니까?또는sed를 사용하여 패턴 뒤의 다음 줄을 편집하는 방법은 무엇입니까?).

이는 전자가 아직 없는 경우에만 force_https_protocol=PROTOCOL_TLSv1_2구성된 행 뒤에 행을 삽입합니다 .[security]

sed '
  $! {
    N
    P
    /^\[security\]\n/ {
      /\nforce_https_protocol=PROTOCOL_TLSv1_2$/ b b
      i\
force_https_protocol=PROTOCOL_TLSv1_2
    }
    :b
    D
  }
  s/^\[security\]$/&\
force_https_protocol=PROTOCOL_TLSv1_2/'

이 스크립트는 다음과 같습니다.

  • 마지막 행( $!)을 제외한 각 행에 대해 개행 문자와 다음 행을 패턴 공간( N)(이미 현재 행을 포함하고 있음)에 추가합니다.
  • 패턴 공간( P)의 첫 번째 라인을 인쇄합니다. 그 라인이라면 [security]...
    • ...그리고 다음 라인은 입니다 force_https_protocol=PROTOCOL_TLSv1_2. 패턴 공간에서 첫 번째 라인을 삭제하고 새로운 사이클( b b, :b D)을 시작합니다.
    • 그렇지 않으면 패턴 공간에서 첫 번째 줄을 삭제하고 새 주기( ) 를 시작하기 전에 force_https_protocol=PROTOCOL_TLSv1_2표준 출력( )으로 인쇄합니다 .i\D
  • 마지막 줄이 이면 [security]줄 바꿈이 뒤따르는 자체로 바꾸고 force_https_protocol=PROTOCOL_TLSv1_2결과를 인쇄합니다(암시된 를 통해 p).

관련 정보