Você não forneceu informações suficientes para que outros reproduzam seu índice de referência. Eu fiz o meu próprio e encontrei o método echo
para ser um pouco mais rápido com dash e ksh, e sobre o mesmo com mksh. A proporção foi muito inferior a 1: 2, mesmo quando houve uma diferença. Obviamente, isso depende de muitas coisas, incluindo o shell, o kernel, a implementação dos utilitários e o conteúdo dos arquivos de dados.
Entre esses dois métodos, não há um vencedor óbvio. A leitura do disco custa praticamente nada porque o arquivo estará no cache. Chamar cat
tem a sobrecarga de bifurcação de um processo externo, enquanto echo
é um shell bultin. Se seu sh
for bash, seu echo
builtin imprimirá seu argumento uma linha por vez, mesmo quando a saída estiver indo para um pipe, o que pode representar um pouco da lentidão. Dash e ksh não fazem isso; normalmente eles têm melhor desempenho que o bash.
Existem várias otimizações que você pode fazer no seu script.
-
Uma otimização óbvia no método
cat
é usar o redirecionamento (<metadata.csv awk …
) ou passarmetadata.csv
como um argumento para o awk. Nos meus testes, o redirecionamento foi muito ligeiramente mais rápido do queecho
e não houve uma diferença mensurável entre o redirecionamento eawk … metadata.csv
. -
Quando você usa uma expansão de variável sem aspas, além de falha horrivelmente se o valor contiver certos caracteres , faz um trabalho extra para o shell, porque ele tem que fazer a divisão e globbing. Sempre use aspas duplas em torno de substituições de variáveis, a menos que você saiba por que precisa omiti-las.
- Da mesma forma, você está analisando a saída de
find
, que irá se afogar em alguns nomes de arquivos e requer trabalho extra. A solução canônica é usarfind -exec
; isso pode ou não ser mais rápido, porque isso também tem que fazer um trabalho extra para iniciar um shell para processar os arquivos. - Eu presumo que o seu script awk é simplificado a partir da coisa real. Com o script que você mostra, assumindo que a primeira coluna do arquivo CSV contém apenas caracteres que não são especiais em expressões regulares, você pode tentar usar o sed; seria mais enigmático, mas poderia ser um pouco mais rápido porque as ferramentas mais especializadas geralmente são mais rápidas. Não há garantias de que você obterá uma melhoria, muito menos uma mensurável.
- Quando você define
ID
, chama um programa externo. Dependendo exatamente do que você está fazendo aqui, isso pode ser feito com as próprias construções de manipulação de strings do shell: elas normalmente não são muito rápidas e não muito poderosas, mas não requerem a chamada de um programa externo.
Ao todo, combinando essas otimizações locais, eu escolheria
#!/bin/ksh
find files/ -type f -exec sh -c '
for FILE do
ID=${FILE//some/thing}
sed '/^$ID\t/ s/\([^\t]*\)\t\([^\t]*\)\t[^\t]*\t[^\t]*\t\([^\t]*\).*/id="" Some="" Thing=""/' metadata.csv
cat "$FILE"
done' _ {} +
Pode haver um algoritmo mais rápido. Você está processando todo o conjunto de metadados para cada arquivo. Especialmente se cada arquivo corresponder apenas a uma linha, isso é um monte de comparações desnecessárias. É provável que seja mais rápido gerar a lista de IDs de nomes de arquivos e agrupá-los com os metadados. Código não testado:
#!/bin/ksh
join -j 1 -t $'\t' -o 2.1,2.2,2.5,1.2 \
<(find files/ -type f | sed 's!/some$!/thing\t&!' | sort) \
<(sort metadata.csv) |
awk -F '\t' '{
print "id =\"" $1 "\" Some=\"" $2 "\" Thing=\" $3 "\"";
system("cat 7" $4 "7"); # Assuming no single quotes in file names
}'