Troca de linhas no arquivo de texto somente onde contendo strings usando sed ou ed? [fechadas]

2

Eu preciso trocar essas linhas, somente onde as strings correspondentes estiverem nas duas linhas:

antes:

REF*CE*-------------------------
REF*1W*-------------------------

depois:

REF*1W*-------------------------
REF*CE*-------------------------

Eu tentei isso, não funcionou:

ed -s testfile.txt <<<$'/REF*CE*/-0,/REF*CE*/+0m/REF*1W*/\nw\nq'
    
por user5586678 28.06.2017 / 20:22

4 respostas

1

sed -e :a -e '$!N;s/^\(REF\*CE.*\)\n\(REF\*1W.*\)/\n/;ta' -e 'P;D' <testfile.txt 
  1. Se não estivermos na última linha, anexe a próxima linha.
  2. Faça uma substituição na linha atual que só ocorre se corresponder a substring containing pattern 1 + newline + substring containing pattern 2 . A substituição inverte as duas subcordas. Após a substituição, volte ao rótulo: a.
  3. Se não houver correspondência Imprima o espaço padrão como está. Em seguida, exclua o espaço do padrão e inicie o ciclo novamente.

Amostra com algumas linhas adjacentes ...

In:

    XEF*CE*------------------------- 
    REF*CE*------------------------- 
    REF*1W*------------------------- 
    REF*2W*------------------------- 

Out:


    XEF*CE*------------------------- 
    REF*1W*------------------------- 
    REF*CE*------------------------- 
    REF*2W*------------------------- 

Mais geralmente para qualquer pattern1 e pattern2

sed -e :a \
    -e "\$!N; s/^\(.*${pattern1}.*\)\n\(.*${pattern2}.*\)/\n/;ta" \
    -e 'P;D' < inputfile
    
por 30.06.2017 / 12:48
0

Podemos obter o efeito desejado colocando a linha correspondente no buffer de retenção, lendo a próxima linha e imprimindo-a, depois trocando o buffer de retenção com o buffer padrão e imprimindo novamente.

bash-4.3$ sed -n '/^REF\*CE/!p;/^REF\*CE/{h;n;p;x;p}' input.txt
some line here
REF*BB*106497026---------------
REF*1W*723266637---------------
REF*CE*NEW JERSEY--------------
SVC*HC^S5102*78.5*78.5**1------
another line there
    
por 01.07.2017 / 00:10
0

Uma solução geral para como trocar duas linhas (possivelmente distantes) que correspondem a expressões regulares específicas com ed :

  1. Copie uma linha para depois da segunda linha.
  2. Move a segunda linha para depois da primeira linha original.
  3. Apague a primeira linha original.

Ou com os comandos de edição ed :

  1. /pat1/t/pat2/
  2. ?pat2?m/pat1/
  3. ?pat1?d

Exemplo com o arquivo

CLP*815900102*2*489.8*101.5*82.29*13*PVJLS03YP0000*13*7
AMT*AU*489.8
REF*6R*00000000002
DTM*472*20160528
CAS*OA*23*306.01
CAS*PR*2*82.29
SVC*HC:99212:25*489.8*101.5**1
AMT*B6*411.43

em que gostaríamos de trocar a primeira linha AMT pela segunda linha CAS . pat1 será ^AMT\*AU e pat2 será ^CAS\*PR . Note que precisamos escapar do * para ser tratado literalmente na expressão regular.

Anotei as alterações abaixo para que seja mais fácil vê-las. O XXX indica a posição atual no arquivo após cada operação.

  1. /^AMT\*AU/t/^CAS\*PR/ produz

    CLP*815900102*2*489.8*101.5*82.29*13*PVJLS03YP0000*13*7
    AMT*AU*489.8        <-- Line copied *from* here
    REF*6R*00000000002
    DTM*472*20160528
    CAS*OA*23*306.01
    CAS*PR*2*82.29
    AMT*AU*489.8        <-- Line copied *to* here (XXX)
    SVC*HC:99212:25*489.8*101.5**1
    AMT*B6*411.43
    
  2. ?^CAS\*PR?m/^AMT\*AU/ produz

    CLP*815900102*2*489.8*101.5*82.29*13*PVJLS03YP0000*13*7
    AMT*AU*489.8
    CAS*PR*2*82.29      <-- line moved here (XXX)
    REF*6R*00000000002
    DTM*472*20160528
    CAS*OA*23*306.01
    AMT*AU*489.8        <-- line previous to this deleted
    SVC*HC:99212:25*489.8*101.5**1
    AMT*B6*411.43
    
  3. ?^AMT\*AU?d produz

    CLP*815900102*2*489.8*101.5*82.29*13*PVJLS03YP0000*13*7
    CAS*PR*2*82.29      <-- the line before this was removed (XXX)
    REF*6R*00000000002
    DTM*472*20160528
    CAS*OA*23*306.01
    AMT*AU*489.8
    SVC*HC:99212:25*489.8*101.5**1
    AMT*B6*411.43
    

Como um "one-liner" fácil de lembrar:

pat1='^AMT\*AU'; pat2='^CAS\*PR'; printf '/%s/t/%s/\n?%s?m/%s/\n?%s?d\nwq\n' "$pat1" "$pat2" "$pat2" "$pat1" "$pat1" | ed -s file

Observe que isso é reversível executando a coisa exata uma segunda vez, ou seja, não importa qual padrão é o primeiro ou o segundo.

    
por 06.09.2017 / 11:30
-1

Eu tenho uma solução simples como esta: Digamos que, se você quiser trocar uma linha que tenha "XXXX" com uma linha que tenha "YYYY" no arquivo, se apenas uma linha tiver "XXXX" e apenas uma tiver "YYYY"

Exemplo de arquivo é assim:    ssss dddd
   aaaa ffff
   ddd rrrr
   ddddd XXXX
   ddddde
   ffff
   ffff
   fff
   eeee YYYY
   ghghgh
   hhhhh

Meu comando 'sed' é /s / XXXX / ZZZZ / g / s / AAAA / XXXX / g; s / ZZZZ / AAAA / g ' Lembre-se de "ZZZZ" string não deve estar no arquivo anyware.

    
por 09.11.2018 / 05:25