Por que redirecionar a saída sed para o mesmo arquivo de entrada deixa minha máquina sem resposta?

13

Eu estava tentando sedsubstituir algumas palavras-chave em um arquivo grande (100 MB). Como eu não conhecia a -iopção (no local), minha primeira tentativa foi redirecionar assim:

sed 's/original/edited/g' file.log >> file.log

o que aconteceu depois disso foi que meu PC parou, quase sem entrada de teclado. Tentei um console diferente Ctrl+ Alt+, F1mas depois de inserir lentamente o nome do usuário, ele também parou. Sem teclado, minha única opção era redefinir o hardware da máquina. Após o login, vi que o file.log tinha cerca de 8 GB.

Eu realmente gostaria de entender por que a execução desse comando foi capaz de deixar o sistema sem resposta e se existem mecanismos no nível do sistema para acionar alertas e interromper o processo ofensivo?

cesarpachon
fonte
7
Esta é uma máquina de núcleo único? Parece muito estranho que isso deva ter deixado um computador moderno de joelhos. Encheu seu disco, sim. Utilizou 100% de um de seus núcleos, sim. Mas um acidente completo?
terdon 6/07/16
Existe algo de peculiar nesse arquivo? se isso não for um problema, você poderia postar seu conteúdo no pastebin?
Sergiy Kolodyazhnyy 06/07/19
Além disso, qual é a quantidade de sua memória? Você poderia nos fornecer uma saída de free -h ?
Sergiy Kolodyazhnyy 06/07/19
Por que usar um editor de fluxo em primeiro lugar quando você deseja alterar um arquivo? ex -sc '%s/original/edited/ge|x' file.logdeve fazer o que quiser da maneira idiomática do UNIX, sem os sed -iefeitos colaterais.
David Ongaro 07/07
Observe que, mesmo se você estiver fazendo isso corretamente (por qualquer um dos métodos que as pessoas estão fornecendo), pode ser arriscado fazer esse tipo de coisa com um arquivo de log pertencente a um processo ativo.
precisa saber é o seguinte

Respostas:

10

Como já foi dito, >>anexa ao arquivo, portanto, seu sedcomando fica sentado lendo as linhas que acabou de produzir e, em seguida, produzindo-as um pouco mais. Se você quiser substituir o arquivo no local, >ainda não iria funcionar, mas você está ciente sedda -iopção, que é definitivamente o que você quer.

Se, no entanto, você tiver certeza absoluta de que deseja anexar a um arquivo que está lendo como fluxo, e deseja fazer apenas uma passagem, considere usar spongeo moreutilspacote;

sed 's/original/edited/g' file.log | sponge >> file.log

spongelê de stdin na memória até o EOF, depois despeja todo o seu conteúdo no stdout, para sedatingir o final do arquivo, parar de ler, fechá-lo e a esponja começará a anexá-lo.

ymbirtt
fonte
2
spongeé um utilitário agradável de saber sobre, mas sedjá tem uma -iopção: -i[SUFFIX], --in-place[=SUFFIX], edit files in place (makes backup if SUFFIX supplied).
Joshua Taylor
@ JoshuaTaylor, OP estava usando >>, o que acrescenta, e não o >que substitui. É verdade que o OP havia mencionado especificamente -ino post e parece ser um caso de uso muito mais comum do que este, mas achei que valia a pena ressaltar que a operação específica que o OP havia postado era possível sem muita folga, se você realmente com certeza é o que você quer fazer.
22868 ymbirtt
1
Eu mencionei aqui porque era a chave na resposta aceita . Dito isto, estou realmente feliz em aprender sobre esponja ; é uma nova ferramenta para minha caixa de ferramentas e digna de um voto positivo apenas por isso.
21416 Joshua Taylor7
1
Ah! Entendo. Vou ajustar minha resposta para deixar isso um pouco mais claro. Além disso, se você gostou sponge, dê uma olhada vipe. moreutilsé apenas um pacote mágico cheio de coisas que você nunca soube que precisava
ymbirtt
18

Seu sedcomando estava tentando ler o arquivo ao qual estava anexando. Ele nunca chegará ao fim do arquivo, mas consumirá muito tempo da CPU tentando. É por isso que ^ C (interromper o processo atual) foi inventado.

waltinator
fonte
Eu não acho que ^ C era uma opção lá ... foi para um HALT, ou seja, nenhum cursor piscando, preso!
EKons
18

Anexar novamente ao arquivo do qual você lê não é, de forma alguma, uma boa idéia, pois você terminará com um arquivo cada vez maior. Se você realmente deseja gravar novamente no arquivo, use o -isinalizador:

sed -i 's/original/edited/g' file.log

ou se você desejar criar um backup antes de fazer alterações, poderá adicionar um sufixo de arquivo ao -isinalizador:

sed -i.bak 's/original/edited/g' file.log

Isso criaria um arquivo chamado file.log.bake, em seguida, faria alterações. O que você fez lá ao tentar anexar ao arquivo do qual está lendo, chamamos na gíria do programador uma corrida de dados, onde diferentes processos disputam a mesma fonte de dados, seja de entrada ou saída . É também por isso que sua máquina parou.

Videonauth
fonte
1
Estou surpreso esta é a resposta aceita, porque ele faz questão nem mesmo o endereço de OP"I really would like to understand why the execution of that command was able to make the system so unresponsive, and if mechanisms exist at the system level to trigger alerts and kill the offending process?"
Steve
@Steve A razão pela qual parou foi a que me dirigi, mas para a segunda parte, você está certo. Não falei disso porque não sabia responder a isso. Testamos o comando após uma discussão extensiva e obtivemos resultados totalmente diferentes em diferentes máquinas e sistemas operacionais. Exemplo: Em uma máquina com arco, ele apenas permite que o arquivo cresça para sempre, mas não deixa a máquina sem resposta. Na minha máquina Ubuntu, eu estava obtendo o mesmo resultado que o questionador, sem chance de interromper o processo. Uma segunda máquina testando o mesmo em uma VM Ubuntu veio à mesma parada.
Videonauth 07/07
Um stracede todo o processo do outro lado didtn reproduzir o resultado e isso na minha máquina e na máquina de um outro usuário. Certamente, existem mecanismos com os quais você pode eliminar aplicativos que não respondem, mas se sua máquina é deixada sem resposta, você fica com apenas uma opção, redefinindo-a. Ainda estou testando isso e, antes de não entender completamente o que está causando o comportamento descrito, não consigo resolver esta parte da pergunta.
Videonauth 07/07
Provavelmente é uma diferença nas configurações do kernel, como um agendador diferente que priorize o IO ou diferenças no driver do disco / sistema de arquivos entre os sistemas. É bom ver a investigação que vocês fizeram, é uma boa informação.
Steve
Se você estiver interessado em outro ponto de dados; Tentei isso em uma máquina CentOS com um arquivo bastante pequeno e fez exatamente o mesmo que minha solução de esponja abaixo. Eu imagino que, para um arquivo pequeno sed, a memória inteira seja armazenada em buffer e depois fechá-la, em vez de manter o controle. Com um arquivo de ~ 100 MB, como no OP, ele cresceu indefinidamente, mas não afetou a máquina.
ymbirtt