Um está correto, o outro não.
du -sh *
(deve ser du -sh -- *
para evitar problemas com nomes de arquivos que começam com -
)
conta com o shell para expandir o glob *
; du
vê todos os arquivos e diretórios não ocultos no diretório atual como argumentos individuais. Isso lida com caracteres especiais corretamente.
ls | xargs du -sh
depende de xargs
para processar a saída de ls
. xargs
divide sua entrada no espaço em branco (pelo menos espaço, tabulação e nova linha, mais com algumas implementações), também compreendendo alguma forma de cotação e executa du
(um (mesmo para uma entrada vazia¹) ou mais invocações) a cada única string separada por espaços em branco como argumentos individuais.
Ambos são equivalentes se o diretório atual não contiver arquivos com espaços em branco, aspas simples, aspas duplas ou caracteres de barra invertida em seus nomes e se houver poucos arquivos suficientes (mas pelo menos um) que xargs
executem apenas um du
invocação, mas não são.
Em termos de eficiência, du -sh *
usa um processo, ls | xargs du -sh
usa pelo menos três. Há um cenário em que a abordagem de pipe funciona, enquanto a glob não: se você tiver muitos arquivos no diretório atual, o shell não poderá executar du
com todos os seus nomes de uma só vez, mas xargs
executará du
quantas vezes forem necessárias para cobrir todos os arquivos. Nesse caso, você verá várias linhas e os arquivos com mais de um link físico poderão ser contados várias vezes.
Veja também Por que * não * analisar 'ls'?
¹ Se não houver nenhum arquivo não oculto no diretório atual du -sh -- *
falhará com um erro do seu shell ou com alguns shells como bash
run du
com um literal *
como argument e du
irão reclamar que o arquivo *
não existe.
Enquanto com ls | xargs du -sh --
, a maioria xargs
implementations (exceções sendo algum BSD) executará du
sem argumento e, portanto, o uso de disco do diretório atual (assim também incluindo o uso de disco do próprio arquivo de diretório e todos os arquivos ocultos e diretórios nele)