Grep para encontrar a linha correta, sed para alterar o conteúdo e depois colocá-lo de volta no arquivo original?

8

Estou tentando alterar uma única palavra em uma linha específica em um arquivo, mas estou tendo problemas para conectar tudo em conjunto.

Basicamente, em uma linha do meu arquivo há uma palavra-chave 'firmware_revision', e nesta linha (e somente nessa linha) eu quero substituir a palavra 'test' pela palavra 'production'.

Então eu posso fazer isso:

grep 'firmware_revision' myfile.py | sed 's/test/production'

Isso selecionará a linha desejada e executará a substituição, mas não consigo descobrir como obter essa nova linha no arquivo original para substituir a linha antiga. Eu obviamente não posso apenas redirecioná-lo de volta para o arquivo, então o que devo fazer?

Mesmo se eu usar temporários, usando grep para obter apenas a linha que preciso, eu perco todos os outros dados no arquivo, então não posso mais redirecionar tudo para um arquivo temporário e substituir o original por a temp.

Editar - Alguém pediu mais informações

Digamos que eu tenha um arquivo cheio de linhas como esta

[
  ('key_name1', str, 'value1', 'Description'),
  ('key_name2', str, 'value2', 'Description'),
  ('key_name3', str, 'value3', 'Description'),
  ('firmware_revision', str, 'my-firmware-name-test', 'Firmware revision name')
]

agora quero escrever um script (idealmente um one-liner) que encontre a linha que contém 'firmware_revision' e altere todas as instâncias da palavra 'test' nessa linha para 'production'. A palavra "teste" pode estar em outros lugares nesse arquivo e eu não quero que isso mude. Então, para ser claro, eu quero mudar a linha acima para

('firmware_revision', str, 'my-firmware-name-production', 'Firmware revision name')

Como faço isso?

    
por John Allard 12.07.2016 / 01:51

2 respostas

21

Tente:

sed -i.bak '/firmware_revision/ s/test/production/' myfile.py

Aqui, /firmware_revision/ age como uma condição. Isso é verdadeiro para linhas que correspondem ao regex firmware_revision e false para outras linhas. Se a condição for verdadeira, o comando que segue é executado. Nesse caso, esse comando é um comando substituto que substitui a primeira ocorrência de test por production .

Em outras palavras, o comando s/test/production/ é executado apenas nas linhas que correspondem ao regex firmware_revision . Todas as outras linhas passam inalteradas.

Por padrão, o sed envia sua saída para o padrão. Você, no entanto, queria mudar o arquivo no lugar. Então, adicionamos a opção -i . Em particular, -i.bak faz com que o arquivo seja alterado no lugar com uma cópia de backup salva com uma extensão .bak .

Se você decidiu que o comando funciona para você e quer viver perigosamente e não criar um backup, então, com o GNU sed (Linux), use:

sed -i '/firmware_revision/ s/test/production/' myfile.py

Por outro lado, no BSD (OSX), a opção -i deve ter um argumento. Se você não quiser manter um backup, forneça um argumento vazio. Assim, use:

sed -i '' '/firmware_revision/ s/test/production/' myfile.py

Editar

Na edição da pergunta, o OP pede a ocorrência de todas test na linha a ser substituída por production . Nesse caso, adicionamos a opção g ao comando substituto para uma substituição global (para essa linha):

sed -i.bak '/firmware_revision/ s/test/production/g' myfile.py
    
por 12.07.2016 / 02:29
4

Em computadores mais antigos com old-school sed que não suportam a opção -i :

TF=$( mktemp -t "${0##*/}"_$$_XXXXXXXX ) && \
trap 'rm -f "$TF"' EXIT HUP INT QUIT TERM && \
sed '/firmware_revision/ s/test/production/' myfile.py >"$TF" && \
mv -f "$TF" myfile.py
    
por 12.07.2016 / 07:08