É sabido que um comando como este:
cat filename | some_sed_command >filename
apaga o nome do arquivo, pois o redirecionamento de saída, sendo executado antes do comando, faz com que o nome do arquivo seja truncado.
Pode-se resolver o problema da seguinte maneira:
cat file | some_sed_command | tee file >/dev/null
mas não tenho certeza se isso funcionaria em qualquer caso: o que acontece se o arquivo (e o resultado do comando sed) for muito grande? Como o sistema operacional pode evitar substituir algum conteúdo que ainda não foi lido? Vejo que também existe um comando de esponja que deve funcionar em qualquer caso: é "mais seguro" que o tee?
command-line
bash
tee
VeryHardCoder
fonte
fonte
Respostas:
Não .
As chances
file
serão truncadas, mas não há garantiacat file | some_sed_command | tee file >/dev/null
que não será truncadafile
.Tudo depende de qual comando é processado primeiro, ao contrário do que se pode esperar, os comandos em um canal não são processados da esquerda para a direita . Não há garantia sobre qual comando será escolhido primeiro; portanto, pode-se pensar nele como escolhido aleatoriamente e nunca confiar que o shell não escolha o ofensor.
Como as chances de o comando incorreto ser escolhido primeiro entre três comandos são menores do que as chances de o comando incorreto ser escolhido primeiro entre dois comandos, é menos provável que
file
seja truncado, mas ainda vai acontecer .script.sh
:Portanto, nunca use algo como
cat file | some_sed_command | tee file >/dev/null
. Usesponge
como Oli sugeriu.Como alternativa, para ambientes mais sofisticados e / ou arquivos relativamente pequenos, pode-se usar uma string here e uma substituição de comando para ler o arquivo antes que qualquer comando seja executado:
fonte
Para
sed
especificamente, você pode usar seu-i
argumento no local. Ele apenas salva de volta no arquivo que abriu, por exemplo:Se você quiser fazer algo mais robusto, supondo que você esteja fazendo mais do que
sed
, sim, você pode armazenar a coisa toda comsponge
(domoreutils
pacote) que "absorverá" todo o stdin antes de gravar no arquivo. É como,tee
mas com menos funcionalidade. Para uso básico, porém, é praticamente uma substituição imediata:Isso é mais seguro? Definitivamente. Provavelmente, ele tem limites; portanto, se você estiver fazendo algo colossal (e não puder editar no local com o sed), convém fazer as edições em um segundo arquivo e depois
mv
o arquivo de volta ao nome do arquivo original. Isso deve ser atômico (para que tudo, dependendo desses arquivos, não seja interrompido se eles precisarem de acesso constante).fonte
Você pode usar o Vim no modo Ex:
%
selecione todas as linhas!
Comando de execuçãox
Salvar e sairfonte
Ah, mas
sponge
não é a única opção; você não precisa obtêmoreutils
-lo para que isso funcione corretamente. Qualquer mecanismo funcionará desde que atenda aos dois requisitos a seguir:Veja bem, o problema bem conhecido ao qual o OP está se referindo é que o shell criará todos os arquivos necessários para que os pipes funcionem antes mesmo de começar a executar os comandos no pipeline, portanto, é o shell que realmente trunca o arquivo de saída (que infelizmente também é o arquivo de entrada) antes que qualquer um dos comandos tivesse a chance de começar a executar.
O
tee
comando não funciona, embora atenda ao primeiro requisito, porque não atende ao segundo requisito: ele sempre criará o arquivo de saída imediatamente após a inicialização, portanto é tão ruim quanto criar um canal direto para o arquivo de saída. (Na verdade, é pior, porque seu uso introduz um atraso aleatório não determinístico antes que o arquivo de saída seja truncado; portanto, você pode pensar que ele funciona, enquanto na verdade não funciona.)Portanto, tudo o que precisamos para resolver esse problema é algum comando que armazene em buffer todas as suas entradas antes de produzir qualquer saída e que seja capaz de aceitar o nome do arquivo de saída como parâmetro, para que não tenhamos que canalizar sua saída para o arquivo de saída. Um desses comandos é
shuf
. Portanto, o seguinte realizará a mesma coisa quesponge
faz:A
--random-source=/dev/zero
parte engana-seshuf
a fazer as coisas sem fazer nenhum embaralhamento, de modo a proteger sua entrada sem alterá-la.fonte