tl; dr
No. >>
é essencialmente "sempre procure final do arquivo" enquanto >
mantém um ponteiro para o último local escrito.
Resposta completa
(Nota: todos os meus testes feitos no Debian GNU / Linux 9).
Outra diferença
Não, eles não são equivalentes. Há outra diferença. Pode se manifestar independentemente de o arquivo de destino existir antes ou não.
Para observá-lo, execute um processo que gere dados e redirecione para um arquivo com >
ou >>
(por exemplo pv -L 10k /dev/urandom > blob
). Deixe rodar e altere o tamanho do arquivo (por exemplo, com truncate
). Você verá que >
mantém seu deslocamento (crescente) enquanto >>
sempre se anexa ao final.
- Se você truncar o arquivo para um tamanho menor (ele pode ter tamanho zero)
>
não se importa, ele escreverá no deslocamento desejado como se nada tivesse acontecido; logo após o truncamento do deslocamento estar além do final do arquivo, isso fará com que o arquivo recupere seu tamanho antigo e cresça ainda mais, os dados ausentes serão preenchidos com zeros (de maneira esparsa, se possível);
>>
será anexado ao novo final, o arquivo aumentará de seu tamanho truncado.
- Se você aumentar o arquivo
>
não se importará, ele escreverá no deslocamento desejado como se nada tivesse acontecido; logo após alterar o tamanho, o deslocamento está em algum lugar dentro do arquivo, isso fará com que o arquivo pare de crescer por um tempo, até que o deslocamento atinja o novo final, então o arquivo aumentará normalmente;
>>
será anexado ao novo final, o arquivo aumentará a partir do tamanho ampliado.
Outro exemplo é acrescentar (com um separado >>
) algo extra quando o processo de geração de dados estiver em execução e gravando no arquivo. Isso é semelhante a ampliar o arquivo.
- O processo de geração
>
gravará no deslocamento desejado e substituirá os dados extras eventualmente.
- O processo de geração
>>
irá pular os novos dados e anexá-los (a condição de corrida pode ocorrer, os dois fluxos podem ser intercalados, ainda assim nenhum dado deve ser substituído).
Exemplo
Isso importa na prática? Existe esta pergunta :
Estou executando um processo que produz muita saída no stdout. Enviando tudo para um arquivo [...] Posso usar algum tipo de programa de rotação de logs?
Esta resposta diz que a solução é logrotate
com a copytruncate
opção que age assim:
Trunque o arquivo de log original depois de criar uma cópia, em vez de mover o arquivo de log antigo e, opcionalmente, criar um novo.
De acordo com o que escrevi acima, o redirecionamento com >
tornará o log truncado grande em pouco tempo. A escassez salvará o dia; nenhum espaço em disco significativo deve ser desperdiçado. No entanto, cada log consecutivo terá cada vez mais zeros à esquerda que são completamente desnecessários.
Porém, se logrotate
criar cópias sem preservar a escassez, esses zeros à esquerda precisarão de mais e mais espaço em disco toda vez que uma cópia for feita. Não investiguei o comportamento da ferramenta, ela pode ser inteligente o suficiente com escassez ou compactação em tempo real (se a compactação estiver ativada). Ainda assim, os zeros podem apenas causar problemas ou, na melhor das hipóteses, serem neutros; nada de bom neles.
Nesse caso, usar em >>
vez de >
é significativamente melhor, mesmo que o arquivo de destino esteja prestes a ser criado ainda.
atuação
Como podemos ver, os dois operadores agem de maneira diferente, não apenas quando começam, mas também mais tarde. Isso pode causar alguma (sutil?) Diferença de desempenho. Por enquanto, não tenho resultados significativos para apoiá-lo ou refutá-lo, mas acho que você não deve assumir automaticamente que o desempenho deles é o mesmo em geral.
>>
é essencialmente "sempre procure o final do arquivo" enquanto>
mantém um ponteiro para o último local escrito. Parece que pode haver alguma diferença sutil de desempenho na maneira como eles funcionam ...>>
usa oO_APPEND
sinalizador paraopen()
. E, na verdade,>
usaO_TRUNC
, enquanto>>
não. A combinação deO_TRUNC | O_APPEND
também seria possível, a linguagem shell simplesmente não fornece esse recurso.O_APPEND
com umlseek()
antes de cada umwrite()
seria diferente, porém, haveria uma sobrecarga adicional de chamada do sistema. (E, claro que não iria funcionar, pois outro processo poderiawrite()
no meio.)