
Eu tenho o seguinte arquivo de texto.
banana
apple
juice
mango
something
Estou procurando por pattern juice
e quero encontrar a segunda linha desse padrão correspondente na ordem inversa (ou seja, 2 linhas acima do padrão correspondente) e substituí-la por coconut
.
Resultado esperado:
coconut
apple
juice
mango
something
Tentei seguir, mas apenas exclui as duas linhas acima e não a exata que estou procurando.
tac foo.txt |sed '/juice/I,+2 d' |tac
mango
something
Acho que ajustar o script acima resolveria o problema, mas não tenho certeza.
Observação: não haverá nenhuma recorrência da correspondência e não precisa ser uma correspondência exata (ou seja, a correspondência também pode ser encontrada em uma linha longa). A correspondência deve diferenciar maiúsculas de minúsculas.
Responder1
Se ed
estiver tudo bem, você precisa editar um arquivo, não um fluxo, e há apenas um juice
:
$ more <<-EOF | ed -s ./tmp.txt
/juice/
-2
c
coconut
.
w
q
EOF
$
Encontre a linha, suba duas linhas, c
hange,
w
rite e q
uit.
Uma variação ainda mais compacta, sugerida por @d-ben-knoble nos comentários:
$ printf '%s\n' '/^juice$/-2s/.*/coconut/' w q | ed -s ./tmp.txt
Responder2
Seguindo sua abordagem,
tac file|sed '/juice/{n;n;s/.*/coconut/}'|tac
/juice/
corresponde a uma linha comjuice
.n;n;
imprime a linha atual e a próxima.s/.*/coconut/
faz a substituição.
Aparentemente você tem o GNU sed, então você também pode usar -z
para colocar o arquivo inteiro na memória e editar diretamente a linha dois acima do suco,
sed -rz 's/[^\n]*(\n[^\n]*\n[^\n]*juice)/coconut\1/' file
[^\n]
significa "não é uma nova linha" e os parênteses ()
capturam o grupo reproduzido pela \1
referência anterior.
Responder3
$ tac file | awk 'c&&!(--c){$0="coconut"} /juice/{c=2} 1' | tac
coconut
apple
juice
mango
something
Responder4
Aqui está outra awk
abordagem, desta vez um método de passagem dupla:
awk 'NR==FNR&&/juice/{m=FNR} NR>FNR&&FNR==m-2{$0="coconut"} (NR>FNR)' file file
- Nós especificamos o arquivoduas vezescomo argumentos de linha de comando, para que seja processado duas vezes.
- Na primeira passagem (onde
FNR
, o contador de linhas por arquivo, é igual aNR
, o contador de linhas global), simplesmente identificamos em qual linhajuice
ocorre o padrão de pesquisa e o armazenamos em uma variávelm
. - Na segunda passagem, definimos o número da linha
m-2
para o texto de substituiçãococonut
. - Como regra geral, imprimimos as linhas incluindo quaisquer modificações, mas apenas na segunda passagem (onde a condição
NR>FNR
é avaliada como “true”).
Se você possui GNU awk
(algumas outras awk
implementações também suportam isso), você pode acelerar um pouco o processo abortando a primeira passagem assim que a correspondência for encontrada usando o nextfile
comando:
awk 'NR==FNR&&/juice/{m=FNR;nextfile} NR>FNR&&FNR==m-2{$0="coconut"} (NR>FNR)' file file